題目描述
已知一個長度爲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個字母產生一個值,所以是二維的而對於區間,一定是由起點和終點組成,所以考慮區間時起點和終點至關重要,