题解 POJ2176 【Folding】

题目链接:Link

Problem

Solution

A+B型拼接的转移方程很显而易见,因此我们只要知道由循环构成的拼接。
可以考虑先预处理出每个数字的位数,然后最小循环节长度可以用kmp $ O(n^2) $ 预处理, $ O(1) $ 求出,由于我不会证最佳循环节长度一定是最小的,$ O(sqrt n) $ 枚举即可,总时间复杂度 $ O(n^3) $。(当然可以四边形不等式成 $ O(n^2 sqrt n) $ )

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,nd[105],f[105][105],pre[105][105],nxt[105][105];
char s[105];
void print(int L,int R)
{
	if(L==R) putchar(s[L]);
	else if(pre[L][R]>0)
	{
		print(L,pre[L][R]);
		print(pre[L][R]+1,R);
	}
	else
	{
		printf("%d(",-(R-L+1)/pre[L][R]);
		print(L,L-pre[L][R]-1);
		putchar(')');
	}
}
int main()
{
	#ifdef local
	freopen("pro.in","r",stdin);
	#endif
	for(int i=2;i<=9;i++) nd[i]=1;
	for(int i=10;i<=99;i++) nd[i]=2;
	nd[100]=3;
	scanf("%s",s+1); n=strlen(s+1);
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++) f[i][i]=1;
	for(int bg=1;bg<=n;bg++)
	{
		nxt[bg][0]=0;
		for(int i=2,j=0;i<=n-bg+1;i++)
		{
			while(j>0&&s[bg+i-1]!=s[bg+j])
				j=nxt[bg][j-1];
			if(s[bg+i-1]==s[bg+j]) j++;
			nxt[bg][i-1]=j;
		}
	}
	for(int len=2;len<=n;len++)
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1;
			int &p=pre[i][j];
			p=i;
			for(int k=i+1;k<j;k++) if(f[i][p]+f[p+1][j]>f[i][k]+f[k+1][j]) p=k;
			f[i][j]=f[i][p]+f[p+1][j];
			int v=len-nxt[i][len-1];
			if(len%v==0)
				for(int k=1;v*k<=len;k++)
					if(len%(v*k)==0&&len/(v*k)>1&&f[i][i+v*k-1]+2+nd[len/(v*k)]<f[i][j])
					{
						f[i][j]=f[i][i+v*k-1]+2+nd[len/(v*k)];
						p=-v*k;
					}
		}
	print(1,n); puts("");
	return 0;
}
原文地址:https://www.cnblogs.com/happyZYM/p/11521095.html