bzoj2213[Poi2011]Difference dp

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2213[Poi2011]Difference dp相关的知识,希望对你有一定的参考价值。

题目描述

已知一个长度为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]$。

设$f[k][j]$表示当前的$sum[k]-sum[j]$,那么需要维护的就是$f[k][j]$的最小值和$f[k][j]$在$sum[j]$不同时的次小值。更新时如果能够用最小值更新答案则用最小值,否则用次小值。然后再用这个$f$去更新最、次小值。

所以同时还要记录最小值和次小值中$j$出现的次数。

因为每次加入一个字符,只有50个$f$值改变了,因此时间复杂度为$O(50n)$。

#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)
{
	if(c[a][b] < sum[b]) ans = max(ans , f[a][b] - g[a][b]);
	else if(d[a][b] < sum[b]) ans = max(ans , f[a][b] - h[a][b]);
	if(f[a][b] < g[a][b])
	{
		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;
}

 

 

以上是关于bzoj2213[Poi2011]Difference dp的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj2213][Poi2011]Difference_动态规划

bzoj2213[Poi2011]Difference dp

BZOJ2529: [Poi2011]Sticks

bzoj2530 [Poi2011]Party

[BZOJ] 2276: [Poi2011]Temperature

BZOJ-2276: [Poi2011]Temperature (单调队列)