题目描述
已知一个长度为n的由小写字母组成的字符串,求其中连续的一段,满足该段中出现最多的字母出现的个数减去该段中出现最少的字母出现的个数最大。求这个个数。
输入
第一行,n
第二行,该字符串
1<=n<=1000000
输出
一行,表示结果
样例输入
10
aabbaaabab
样例输出
3
题解
dp
令 sum[i][j] 表示前 i 个字母中 j 的出现次数,那么题目所求的是 Max((sum[r][i]−sum[l−1][i])−(sum[r][j]−sum[l−1][j]))=Max((sum[r][i]−sum[r][j])−(sum[l−1][i]−sum[l−1][j]))
其中 j 必须在 [l,r] 中出现过,即 sum[r][j]−sum[l−1][j]>0 。
所以我们可以扫一遍右端点,要求的就是满足 sum[r][j]−sum[l−1][j]>0 的最小的 sum[l−1][i]−sum[l−1][j] 。
更新时首先想到一点,最小值可以直接更新,但次小值不能随便更新,因为对于每一对a,b,都要算出其最大值,能用最小值更新答案就用最小值更新答案,如果不能,则用次小值更新。
总结: 对于此题,有26个字母,每一个字母都可以和前面的25个字母产生一个值,所以是二维的,而对于区间,一定是由起点和终点组成,所以考虑区间时起点和终点至关重要,分析题目中的维度,所不定可以给解题带来很好的思路。
#include <cstdio>
#include <algorithm>
#define K 26
using namespace std;
int sum[K] , f[K][K] , g[K][K] , c[K][K] , h[K][K] , d[K][K] , ans;
char str[1000010];
void update(int a , int b)//f[a][b]++;
{
if(c[a][b] < sum[b]) ans = max(ans , f[a][b] - g[a][b]);//OK
else if(d[a][b] < sum[b]) ans = max(ans , f[a][b] - h[a][b]);//OK
if(f[a][b] < g[a][b])//OK
{
if(c[a][b] < sum[b]) h[a][b] = g[a][b] , d[a][b] = c[a][b];
g[a][b] = f[a][b] , c[a][b] = sum[b];
}
else if(c[a][b] < sum[b] && f[a][b] < h[a][b]) h[a][b] = f[a][b] , d[a][b] = sum[b];
}
int main()
{
int n , i , j , t;
scanf("%d%s" , &n , str + 1);
for(i = 1 ; i <= n ; i ++ )
{
t = str[i] - 'a' , sum[t] ++ ;
for(j = 0 ; j < K ; j ++ )
if(t != j)
f[t][j] ++ , update(t , j) , f[j][t] -- , update(j , t);
}
printf("%d\n" , ans);
return 0;
}//自强不息,厚德载物!!!
题目描述
已知一个长度为n的由小写字母组成的字符串,求其中连续的一段,满足该段中出现最多的字母出现的个数减去该段中出现最少的字母出现的个数最大。求这个个数。
输入
第一行,n
第二行,该字符串
1<=n<=1000000
输出
一行,表示结果
样例输入
10
aabbaaabab
样例输出
3
题解
dp
令 sum[i][j] 表示前 i 个字母中 j 的出现次数,那么题目所求的是 Max((sum[r][i]−sum[l−1][i])−(sum[r][j]−sum[l−1][j]))=Max((sum[r][i]−sum[r][j])−(sum[l−1][i]−sum[l−1][j]))
其中 j 必须在 [l,r] 中出现过,即 sum[r][j]−sum[l−1][j]>0 。
所以我们可以扫一遍右端点,要求的就是满足 sum[r][j]−sum[l−1][j]>0 的最小的 sum[l−1][i]−sum[l−1][j] 。
更新时首先想到一点,最小值可以直接更新,但次小值不能随便更新,因为对于每一对a,b,都要算出其最大值,能用最小值更新答案就用最小值更新答案,如果不能,则用次小值更新。
总结: 对于此题,有26个字母,每一个字母都可以和前面的25个字母产生一个值,所以是二维的而对于区间,一定是由起点和终点组成,所以考虑区间时起点和终点至关重要,