BZOJ 1090 字符串折叠(区间DP)
很明显的区间DP,设dp[l][r]表示[l,r]区间的字符串折叠后的最小长度。
可以通过两种方向转移,dp[l][r]=min(dp[l][i]+dp[i+1][r]).
另一种是折叠,dp[l][r]=min(dp[l][l+k-1]+cal((r-l+1)/k)+2).其中k是能整除(r-l+1)的数且区间能够折叠成k份,cal()函数计算数字的位数。
另外用了线段树维护hash值,可以每次验证logn。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=105; //Code begin... char s[N]; int dp[N][N], n; LL seg[N<<2], power[N]; void push_up(int p, int L){seg[p]=(seg[p<<1]*power[L>>1]+seg[p<<1|1])%MOD;} void init(int p, int l, int r){ if (l<r) { int mid=(l+r)>>1; init(lch); init(rch); push_up(p,r-l+1); return ; } seg[p]=s[l]; } LL query(int p, int l, int r, int L, int R) { if (L>r||R<l) return 0; if (L<=l&&R>=r) return seg[p]*power[R-r]%MOD; int mid=(l+r)>>1; return (query(lch,L,R)+query(rch,L,R))%MOD; } int qiu(int x){ if (x<10) return 1; else if (x<100) return 2; else return 3; } int cal(int l, int r, int k) { LL val=query(1,1,n,l,l+k-1); bool flag=1; for (int i=l+k; i<=r; i+=k) if (val!=query(1,1,n,i,i+k-1)) {flag=0; break;} if (!flag) return INF; else return dp[l][l+k-1]+qiu((r-l+1)/k)+2; } int dfs(int l, int r) { if (~dp[l][r]) return dp[l][r]; if (l==r) return dp[l][r]=1; int ans=r-l+1; FO(i,l,r) ans=min(ans,dfs(l,i)+dfs(i+1,r)); FOR(i,1,(r-l+1)/2) if ((r-l+1)%i==0) ans=min(ans,cal(l,r,i)); return dp[l][r]=ans; } int main () { mem(dp,-1); power[0]=1; FOR(i,1,100) power[i]=power[i-1]*31%MOD; scanf("%s",s+1); n=strlen(s+1); init(1,1,n); dfs(1,n); printf("%d\n",dp[1][n]); return 0; }