BZOJ 1068: [SCOI2007]压缩
Sol
区间DP.这个区间DP需要三维, \(f[i][j][k]\) 表示\([i,j]\) 这个区间中是否存在 \(M\) .
转移有两种,一种是这个区间存在 \(M\) ,那么直接枚举 \(M\) 的位置就可以了;另一种是没有 \(M\) ,那么从中间劈来,如果两边一样,显然是左边没有 \(M\) 的答案+1就可以了,还有种情况就是 左边压缩右边不压缩就行了.
随便加个记忆化搜索就行了,出口就是 \(L==R\) 如果 \(k==0\) 显然答案为1; \(k==1\) 不存在,赋个大数就可以了.
PS:这题一开始写了个70分的...不是前七十...中间有WrongAnswer的.
Code
/************************************************************** Problem: 1068 User: BeiYu Language: C++ Result: Accepted Time:20 ms Memory:1312 kb ****************************************************************/ #include<cstdio> #include<cstring> #include<iostream> using namespace std; #define debug(a) cout<<#a<<"="<<a; const int N = 55; const int INF = 55; char c[N]; int f[N][N][2]; int pd(int l,int r){ int mid=(l+r)>>1; for(int i=l,j=mid+1;j<=r;i++,j++) if(c[i]!=c[j]) return 0; return 1; } int DP(int L,int R,int k){ int &res=f[L][R][k];if(~res) return res; if(L>R) return res=0;if(L==R){ if(k) return res=INF;else return res=1; } int lenth=R-L+1;res=lenth; if(k){ for(int i=L;i<R;i++){ res=min(res,DP(L,i,0)+DP(i+1,R,0)+1); res=min(res,DP(L,i,0)+DP(i+1,R,1)+1); res=min(res,DP(L,i,1)+DP(i+1,R,0)+1); res=min(res,DP(L,i,1)+DP(i+1,R,1)+1); }return res; }if((lenth&1)==0&&pd(L,R)) res=min(res,DP(L,L+(lenth>>1)-1,0)+1); for(int i=L;i<R;i++) res=min(res,DP(L,i,0)+R-i); return res; } int main(){ scanf("%s",c+1);int n=strlen(c+1); memset(f,-1,sizeof(f));cout<<min(DP(1,n,0),DP(1,n,1))<<endl; return 0; }