bzoj1090: [SCOI2003]字符串折叠
区间dp。
用f[l][r]表示区间[l,r]最短能缩到多短。
然后状态转移方程有俩种
1.不折叠 f[l][r]=f[l][i]+f[i+1][r]. (l=<i<r)
2.折叠 f[l][r]=f[l][l+i-1]+2+(数字是几) (1<=i<n)
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 200 + 10; char s[maxn]; int f[maxn][maxn]; int h(int i,int n) { if(n/i<10) return 1; if(n/i<100) return 2; return 3; } bool same(int l,int r,int k) { for(int i=k;i+k<=(r-l+1);i+=k) for(int j=l;j<=(l+k-1);j++) if(s[j]!=s[i+j]) return 0; return 1; } int dp(int l,int r) { if(l==r) return 1; if(f[l][r]) return f[l][r]; int &res=f[l][r]; int n=res=r-l+1; for(int i=l;i<r;i++) res=min(res,dp(l,i)+dp(i+1,r)); for(int i=1;i<n;i++) if(n%i==0) if(same(l,r,i)) res=min(res,dp(l,l+i-1)+2+h(i,n)); return res; } int main() { scanf("%s",s+1); printf("%d\n",dp(1,strlen(s+1))); return 0; }