<胡策day> 10.26 T1 最大子串权值
来源:互联网 发布:软件测试的专业术语 编辑:程序博客网 时间:2024/06/04 18:59
*PS:一上来第一题就是一个思维题qwq,emmm…考场上只打了个暴力,果断60分滚粗。%%那些在考场上打出正解的dalao。
题目来源:钟长者(侵删)
【问题描述】
你是能看到第一题的 friends 呢。 ——hja
何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx。 何大爷今天为字符串定义了新的权值计算方法。一个字符串由小写字母组成,字符串的权值被定义为其中出现次数最多的字符的次数减去出现次数最少的字符的次数。(注意,在讨论出现最少的字符的时候,该字符必须至少出现一次)现在何大爷给你一个字符串,何大爷想知道这个字符串的所有子串中权值最大的权值是多少?
【输入格式】
第一行一个整数n,代表字符串的长度。
接下来一行n个小写字母,代表该字符串。
【输出格式】
一行一个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
对于30%的数据, 1 ≤ n ≤ 100。
对于60%的数据, 1 ≤ n ≤ 1000。
对于100%的数据, 1 ≤ n ≤ 106.
60 分暴力
n^2 枚举区间,更新答案。
代码
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;int N,maxn,minn,ans=0;int app[30]; char a[1000010];int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&N); scanf("%s",a); for(int i=0;i<N;++i) { memset(app,0,sizeof(app)); maxn=minn=a[i]-'a'; ++app[a[i]-'a']; for(int j=i+1;j<N;++j) { int k=a[j]-'a'; ++app[k]; if(maxn==k&&minn!=k) maxn=k; else { swap(maxn,minn); for(int e=0;e<26;++e) if(app[e]) { if(app[e]>app[maxn]) maxn=e; if(app[e]<app[minn]) minn=e; } } ans=max(ans,app[maxn]-app[minn]); } } printf("%d",ans); return 0;}
满分做法
发现10^6 nlogn很吃力,考虑常数比较大的 O(n)的做法。
我们发现 n^2的做法中有很多不必要的转移,枚举了很多对答案没有贡献的区间。所以考虑能不能把多余的枚举去掉?
emmm…既然答案肯定是一个字母的出现次数 - 另一个字母的出现次数。
so??
定义 sum[k] 为当前扫到第i个数时1~i中字母k出现的次数。若k为最优子串的出现次数最多的那个字符,那我们需要枚举a~z (!=k)并把它当做出现次数最少的那个字符来更新答案,设枚举的字符为j。可知被更新的最优区间的答案为 sum[k]-sum[j]-(sum’[k]-sum’[j]) ,其中的sum’[k]-sum’[j]表示 1~i 中 的字符k的次数 - 字符j的次数最少的那个区间(1~x)的答案(可能为负数),就相当于从1~i 中舍弃了1~x 这个区间来得到最优区间的答案。反之同理。
sum’[k]-sum’[j]可以在之前就记录下来,另开一个数组f[k][j]表示。
但是我们枚举到的最优区间可能并不包含j,这样算出的答案就是错的,所以我们还需记录一个last[j]表示j最后出现的位置,pos[k][j]记录f[k][j]的右端点,如果last[j]==pos[k][j],则需要把最优区间的答案-1(把前面的j算上)。
特判:sum为0的情况
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;int N,ans;int sum[30],last[30];int f[30][30],pos[30][30];char s[1000010];int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&N); scanf("%s",s+1); for(int i=1;i<=N;++i) { int k=s[i]-'a'; ++sum[k]; last[k]=i; for(int j=0;j<26;++j) if(sum[j]&&j!=k) { ans=max(ans,sum[k]-sum[j]-f[k][j]-(last[j]==pos[k][j])); ans=max(ans,sum[j]-sum[k]-f[j][k]-(last[j]==pos[j][k])); } for(int j=0;j<26;++j) { if(f[k][j]>sum[k]-sum[j]) f[k][j]=sum[k]-sum[j],pos[k][j]=i; if(f[j][k]>sum[j]-sum[k]) f[j][k]=sum[j]-sum[k],pos[j][k]=i; } } printf("%d",ans); return 0;}
- <胡策day> 10.26 T1 最大子串权值
- <胡策day> 10.30 T1 小学数学
- [T1 Silverlight Training] Day 1
- GDKOI2016 Day 1 T1 魔卡少女
- NOIP2016#模拟考试 Day.1# T1 洗澡
- NOIP2016#模拟考试 Day.2# T1 改错
- 济南学习 Day 3 T1 am
- 济南学习 Day 3 T1 pm
- 济南学习 Day 4 T1 am
- 济南学习 Day 4 T1 pm
- 济南学习 Day 5 T1 am
- 济南学习 Day 5 T1 晚
- 济南学习 Day 5 T1 pm
- NOIP 2013 day 2 t1 t2
- <互测 day> 11.6 T1 谜团 (mituan)
- 【NOI2006 Day2 T1】最大获利
- 【NOIP 2013 DAY.1】T1 转圈游戏【codevs 3285】
- [NOIP 2015] Day.1 T1 神奇的幻方 [模拟]
- c++程序入门(三)——用结构和类分别实现复数加法和乘法
- Ontrack EasyRecovery 12 v12.0中文版下载附激活码
- 51Nod 1670 打怪兽
- linux--线性表(大话数据结构)
- mysql 严格模式 Strict Mode说明
- <胡策day> 10.26 T1 最大子串权值
- maven在编译时报栈溢出的解决办法
- 安装Vue.js
- 实现人工智能之路
- 是谁养鱼的解决方案
- Oracle之hint研究查询生效范围
- C++ 指针/数组指针操作
- Python第一阶段复习
- JQueryEasyUI