Codeforces 825F String Compression DP(最小循環節)

題意:字符串s,s能壓縮成c1s1c2s2..cksk時,表示把s1寫c1次,s2寫c2次...能得到s
|s|<=8000,問s能壓縮後最小長度爲?

設dp[i] 前綴i壓縮後的最小長度
dp[i]=min(dp[i],dp[j]+"s[j+1]..s[i]") 最後一段肯定用最小循環節來表示

求出後綴i的next數組時,就能知道i-j(j>=i)最小循環節的長度 O(n^2)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> ii;
const int inf=0x3f3f3f3f;
const int N=8e3+20;
char s[N];
int f[N];
void getfail(char s[],int fail[],int n)
{
	fail[1]=0;
	for(int i=1;i<n;i++)
	{
		int p=fail[i];
		while(p&&s[p+1]!=s[i+1]) 
			p=fail[p];
		fail[i+1]=p+(s[p+1]==s[i+1]);
	}
}
int calc(int x)
{
	int res=0;
	while(x) res++,x/=10;
	return res;
}
int dp[N];
int main()
{
	while(scanf("%s",s+1)!=EOF)
	{
		int n=strlen(s+1);
		memset(dp,inf,sizeof(dp));
		dp[0]=0;
		for(int i=1;i<=n;i++)
		{
			getfail(s+i-1,f,n-i+1);
			for(int j=i;j<=n;j++)
			{
				int len=j-i+1,x=len-f[len],num;
				if(len%x==0)
					num=len/x;
				else
					num=1;
				dp[j]=min(dp[j],dp[i-1]+len/num+calc(num));		
			}
		}
		cout<<dp[n]<<endl;
	}
	return 0;
}


發佈了625 篇原創文章 · 獲贊 4 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章