大意:
给定一字符串,定义权值为串中出现次数最多字符 - 出现次数最少字符,求权值最大子串
字符串长度 n <= 10^6,保证都由小写字母组成
考完试悔的肠子都青了的题……
明明离正解那么近了……
考场思路:
发现求区间l,r中字符a出现次数-字符b出现次数,用前缀和可以表示为
即
而我们发现,
min(Sa−Sb)
是可以被维护的……
又因为扫描到某一位置时,作为最多字符更新目前最优答案的只可能是该位置上的字符
所以每一位置for一遍26个字符,寻找可能作为最小值的字符
还有问题……
虽然维护了
min(Sa−Sb)
,并且可以保证该位置出现在当前位置之前
但不一定该位置与当前位置组成的区间里存在字符b
对此的处理方法:记录b最后出现的位置和
min(Sa−Sb)
的位置
因为注意到
min(Sa−Sb)
的性质,是只有在
Sb
更新时才会增加的
所以
min(Sa−Sb)
的位置一定为b存在的位置
如果
Posmin(Sa−Sb)=PosLastb
,就让答案强行 - -,表示b + 1
%%%考场正解的summer && wyh
后来wyh讲了更直观的思路
“要suma和sumb的差值最大,就减去sumb比suma多的最多的区间”
ssssrO
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
char s[1000010];
int n;
int sum[30],mnum[30][30],mpos[30][30];
int last[1000010];
int ans;
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
scanf("%s",s + 1);
memset(last,-1,sizeof(last));
for(int i = 1;i <= n;i ++){
int t = s[i] - 'a';
sum[t] ++;
last[t] = i;
for(int k = 0;k <= 25;k ++){
if(k == t)continue;
if(mnum[k][t] > sum[k] - sum[t])
mnum[k][t] = sum[k] - sum[t],mpos[k][t] = i;
}
for(int k = 0;k <= 25;k ++){
if(k == t || !sum[k])continue;
int tmp = sum[t] - sum[k] - mnum[t][k];
if(mpos[t][k] == last[k])tmp --;
ans = max(ans,tmp);
}
}
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
明明有思路的题放着不打,自己去T2找恶心……
但后来检查考场代码思路确实凌乱……
Tips:
用适当的变量名代替表达式使代码更简洁
对自己的思路有信心……