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;
}
View Code

 

posted @ 2017-03-07 18:19  free-loop  阅读(173)  评论(0编辑  收藏  举报