压缩
题目链接:https://ac.nowcoder.com/acm/problem/20252
如果没有M的话,是一个正常的区间dp,我们可以列出来它的转移方程
① dp[l][r]=min( dp[l][r] , dp[l][j] + dp[j+1][r] );
如果当前区间(l,r)前半段和后半段相同,那就将它压缩一半然后加上一个R:
② dp[l][r]=min( dp[l][r] , dp[l][j] + 1 );
但是现在有一个M,因此就再加一种情况,定义dp[l][r][0/1],表示区间(l,r)有M和没有M时的最小值。
没有M时,我们要改一下①的式子,变成:
① dp[l][r][0]=min( dp[l][j][0] + r-j , dp[l][r][0]); (l<= j <=r)
因为对于后半段(j+1,r),因为没有M,要是压缩的话,会把(l,r)整个区间都压缩,所以后半段是不能压缩的,长度就是 r-j
前半段和后半段正好相等的时候:
② dp[l][r][0]=min( dp[l][r][0] , dp[l][(l+r)/2][0] + 1 );
有M的时候,枚举m的位置:
③ dp[l][r][1] = min( dp[l][r][1] , min( dp[l][j][1] , dp[l][j][0] ) + 1 + min( dp[j+1][r][1] , dp[j+1][r][0] ) );
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <stack> #include <queue> #include <cmath> #define ll long long #define pi 3.1415927 #define inf 0x3f3f3f3f #define mod 1000000007 using namespace std; #define _int __int128_t inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return f*x; } void print(int x) { if(x < 0) {putchar('-');x = -x;} if(x/10) print(x/10); putchar(x%10+'0'); } int n,m; int dp[1005][1005][2]; string s; int judge(int l,int r) { int mid=(l+r)/2; for(int i=l;i<=mid;++i) if(s[i]!=s[mid+1+i-l]) return 0; return 1; } int main () { int T,i,t,j,k,p,sum=0; cin>>s; int len=s.length(); dp[0][0][0]=1; for(int i=1;i<=len;++i){ for(int l=0;l<len-i+1;++l){ int r=l+i-1; dp[l][r][0]=i;dp[l][r][1]=i; for(int j=l;j<=r;++j){ dp[l][r][0]=min(dp[l][j][0]+r-j,dp[l][r][0]); dp[l][r][1]=min(dp[l][r][1],min(dp[l][j][1],dp[l][j][0])+1+min(dp[j+1][r][1],dp[j+1][r][0])); } if(i%2==0 && judge(l,r) ) dp[l][r][0]=min(dp[l][r][0],dp[l][(l+r)/2][0]+1); } } p=min(dp[0][len-1][0],dp[0][len-1][1]); cout<<p<<endl; return 0; }