[SCOI2007]压缩(区间dp)
神仙题,看了半天题解才看明白。。。
因为题目里说如果没有m,会自动默认m在最前面。
我们设计状态为dp[l][r][0/1]为在区间l到r中有没有m的最小长度。
转移:枚举我们要压缩的起点,dp[l][i][1]+dp[i+1][r][1]+1,加一是指我们要压缩后半段,在断点处加上一个m。
如果我们不压缩后半段,那转移就为dp[l][i][1]+r-i,因为后面不动,就直接加上。
如果发现它可以压缩,直接dp[l][mid][0]+1,注意tag为0。
Code
#include<iostream> #include<cstdio> #include<cstring> #define N 55 using namespace std; int dp[N][N][2],n; char s[N]; inline bool pd(int l,int r){ if((r-l+1)%2==1)return 0; int len=(r-l+1)/2; for(int i=l;i<=l+len-1;++i) if(s[i]!=s[i+len])return 0; return 1; } int dfs(int l,int r,int tag){ if(dp[l][r][tag])return dp[l][r][tag]; int ans=r-l+1; if(ans==1)return ans; if(tag) for(int i=l;i<r;++i)ans=min(ans,dfs(l,i,1)+1+dfs(i+1,r,1)); for(int i=l;i<r;++i)ans=min(ans,dfs(l,i,tag)+r-i); if(pd(l,r))ans=min(ans,dfs(l,(l+r)>>1,0)+1); return dp[l][r][tag]=ans; } int main(){ scanf("%s",s); n=strlen(s); printf("%d",dfs(0,n-1,1)); return 0; }