bzoj1090(SCOI2003)字符串折叠
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1090
像这种的一看就是区间dp。涉及合并什么的。
需要注意的是那个括号前的数字不一定是一位!
而且所有涉及区间的用的都是已经算好的dp值,比如那个折叠的地方,不是直接的长度,而是那一块的dp值!
不需要把dp想复杂。只要考虑设计了状态之后怎样转移。
转移常常需要分类讨论,比如这里就分类一下该区间要不要整体折叠。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[105][105],n; char a[105]; int check(int l,int k,int r) { int x=k-l,y=r-k+1; if(y%x)return 0; int s=y/x; for(int i=l;i<k;i++) for(int j=1;j<=s;j++) if(a[i+j*x]!=a[i])return 0; return 1; } int cal(int a) { int ret=0; while(a)a/=10,ret++; return ret; } int main() { cin>>(a+1);n=strlen(a+1); memset(dp,1,sizeof dp); for(int i=1;i<=n;i++)dp[i][i]=1; for(int d=2;d<=n;d++) for(int l=1;l<=n-d+1;l++) { int r=l+d-1;dp[l][r]=r-l+1;///////// for(int j=l;j<r;j++) { dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]); if(check(l,j+1,r))dp[l][r]=min(dp[l][r],dp[l][j]+2+cal((r-l+1)/(j+1-l))); ///不是s,而是dp[l][j] } } printf("%d",dp[1][n]); return 0; }