zoukankan      html  css  js  c++  java
  • CF932G Palindrome Partition

    思路

    首先把字符串变为(S[1]S[n]s[2]s[n-1] dots)
    这样原来的一个合法的划分方案就变成了用k个长度为偶数的回文子串划分的方案,
    然后直接DP,对i位置,可转移的位置就是它的几个回文后缀,在PAM上跳fail即可
    但是复杂度是假的,一旦串的每个字符都相同,就需要跳(O(n))次fail,总复杂度变成了(O(n^2))

    所以有这样一个性质,对一个节点x,它的所有fail的len最多是log个等差数列,因为对于长度大于(frac{len}{2})的情况,由于回文树的性质,长度一定是一个等差数列,每次len/2,所以有log段

    考虑直接对这log端的贡献转移,在当前的位置i,设之前三个位置为a1,a2,a3(a1>a2>a3),由于回文串的性质S[i-a1,i-d]=S[i-a2,i],S[i-a2,i-d]=S[i-a3,i],所以a2,a3在i-d处已经被统计过了,加上i-a1的贡献即可

    复杂度(O(nlog n))

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MOD = 1e9+7;
    int trans[1000100][26],fail[1000100],Nodecnt,len[1000100],last,n,dp[1000100],pre[1000100],f[1000100],inc[1000100];
    char mids[1000100],s[1000100];
    int New_state(int _len){
        len[Nodecnt]=_len;
        return Nodecnt++;
    }
    int get_fail(int p,int n){
        while(mids[n-len[p]-1]!=mids[n])
            p=fail[p];
        return p;
    }
    void insert(int n){
        int cur=get_fail(last,n);
        if(!trans[cur][mids[n]]){
            int t=New_state(len[cur]+2);
            fail[t]=trans[get_fail(fail[cur],n)][mids[n]];
            trans[cur][mids[n]]=t;
            inc[t]=len[t]-len[fail[t]];
            if(inc[t]==inc[fail[t]])
                pre[t]=pre[fail[t]];
            else
                pre[t]=fail[t];
        }
        last=trans[cur][mids[n]];
    }   
    int main(){
        mids[0]=-1;
        New_state(0);
        fail[0]=1;
        New_state(-1);
        last=0;
        scanf("%s",s+1);
        n=strlen(s+1);
        // printf("n=%d
    ",n);
        dp[0]=1;
        int inq=0;
        for(int i=1;i<=n/2;i++){
            mids[++inq]=s[i]-'a';
            insert(inq);
            for(int j=last;j;j=pre[j]){
                f[j]=dp[inq-len[pre[j]]-inc[j]];
                if(pre[j]!=fail[j])
                    f[j]=(f[j]+f[fail[j]])%MOD;
                if(!(inq&1))
                    dp[inq]=(dp[inq]+f[j])%MOD;
            }
            mids[++inq]=s[n-i+1]-'a';
            insert(inq);
            for(int j=last;j;j=pre[j]){
                f[j]=dp[inq-len[pre[j]]-inc[j]];
                if(pre[j]!=fail[j])
                    f[j]=(f[j]+f[fail[j]])%MOD;
                if(!(inq&1))
                    dp[inq]=(dp[inq]+f[j])%MOD;
            }
        }
        // for(int i=1;i<=n;i++)
        //     putchar(mids[i]+'a');
        // putchar('
    ');
        printf("%d
    ",dp[n]);   
        return 0;
    }
    
  • 相关阅读:
    Django(72)Django认证系统库--djoser
    Django(71)图片处理器django-imagekit
    python进阶(21)typing模块--类型提示支持
    Jmeter 参数化-文件和参数同时上传的场景
    Java线程监控之 jvisualvm 和 jstack
    操作系统监控
    Redis安装部署
    Mac下charles安装及配置
    Prometheus 监控平台部署
    Nginx配置(九)
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10748119.html
Copyright © 2011-2022 走看看