【bzoj2213】[Poi2011]Difference dp
2017-10-17 20:42
239 查看
题目描述
已知一个长度为n的由小写字母组成的字符串,求其中连续的一段,满足该段中出现最多的字母出现的个数减去该段中出现最少的字母出现的个数最大。求这个个数。
输入
第一行,n
第二行,该字符串
1<=n<=1000000
输出
一行,表示结果
样例输入
10
aabbaaabab
样例输出
3
题解
dp
令sum[i][j]sum[i][j]表示前ii个字母中jj的出现次数,那么题目所求的是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]))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]))
其中jj必须在[l,r][l,r]中出现过,即sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0。
所以我们可以扫一遍右端点,要求的就是满足sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0的最小的sum[l−1][i]−sum[l−1][j]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]sum[i][j]表示前ii个字母中jj的出现次数,那么题目所求的是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]))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]))
其中jj必须在[l,r][l,r]中出现过,即sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0。
所以我们可以扫一遍右端点,要求的就是满足sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0的最小的sum[l−1][i]−sum[l−1][j]sum[l−1][i]−sum[l−1][j]。
更新时首先想到一点,最小值可以直接更新,但次小值不能随便更新,因为对于每一对a,b,都要算出其最大值,能用最小值更新答案就用最小值更新答案,如果不能,则用次小值更新。
总结: 对于此题,有26个字母,每一个字母都可以和前面的25个字母产生一个值,所以是二维的而对于区间,一定是由起点和终点组成,所以考虑区间时起点和终点至关重要,
已知一个长度为n的由小写字母组成的字符串,求其中连续的一段,满足该段中出现最多的字母出现的个数减去该段中出现最少的字母出现的个数最大。求这个个数。
输入
第一行,n
第二行,该字符串
1<=n<=1000000
输出
一行,表示结果
样例输入
10
aabbaaabab
样例输出
3
题解
dp
令sum[i][j]sum[i][j]表示前ii个字母中jj的出现次数,那么题目所求的是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]))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]))
其中jj必须在[l,r][l,r]中出现过,即sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0。
所以我们可以扫一遍右端点,要求的就是满足sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0的最小的sum[l−1][i]−sum[l−1][j]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]sum[i][j]表示前ii个字母中jj的出现次数,那么题目所求的是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]))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]))
其中jj必须在[l,r][l,r]中出现过,即sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0。
所以我们可以扫一遍右端点,要求的就是满足sum[r][j]−sum[l−1][j]>0sum[r][j]−sum[l−1][j]>0的最小的sum[l−1][i]−sum[l−1][j]sum[l−1][i]−sum[l−1][j]。
更新时首先想到一点,最小值可以直接更新,但次小值不能随便更新,因为对于每一对a,b,都要算出其最大值,能用最小值更新答案就用最小值更新答案,如果不能,则用次小值更新。
总结: 对于此题,有26个字母,每一个字母都可以和前面的25个字母产生一个值,所以是二维的而对于区间,一定是由起点和终点组成,所以考虑区间时起点和终点至关重要,
相关文章推荐
- 【BZOJ2213】[Poi2011]Difference DP
- bzoj 2213: [Poi2011]Difference
- 【bzoj2213】[Poi2011]Difference dp
- bzoj2213: [Poi2011]Difference(思维题)
- BZOJ2213: [Poi2011]Difference
- bzoj 2213: [Poi2011]Difference 乱搞
- BZOJ2213: [Poi2011]Difference
- BZOJ2213 [Poi2011]Difference 【乱搞】
- BZOJ 2213: [Poi2011]Difference
- [bzoj2213][Poi2011]Difference_动态规划
- bzoj2216: [Poi2011]Lightning Conductor 决策单调性
- bzoj 2527: [Poi2011]Meteors -- 整体二分
- 【POI2011】【BZOJ2280】Plot
- BZOJ2216 [Poi2011]Lightning Conductor 【决策单调性dp】
- BZOJ 2212 [Poi2011]Tree Rotations 线段树合并
- bzoj2216[POI2011] Lightning Conductor
- bzoj2215[POI2011]Conspiracy
- BZOJ2526 [Poi2011]Inspection
- BZOJ2530 [Poi2011]Party
- [整体二分+树状数组]BZOJ 2527——[Poi2011]Meteors