zoukankan      html  css  js  c++  java
  • Codeforces 932G

    Codeforces 932G - Palindrome Partition

    题意

    给定一个字符串 (s),要求将 (s) 划分为 (t_1,t_2,dots,t_k),其中 (k) 是偶数,且 (t_i=t_{k-i+1}),求这样的划分方案数。

    (|S|le 10^6)

    分析

    构造字符串(t=s[1]s[n]s[2]s[n-1]s[3]s[n-2]dots s[n/2]s[n/2+1]),问题就等价于求(t)的最小偶回文划分方案数,对(t)构建回文自动机。根据这篇文章的证明,(s) 的所有回文后缀按照长度排序后,可以划分成( ext{log|s|})段等差数列。在回文自动机上的每个结点(u)多维护两个信息,(diff[u])(slink[u])(diff[u]=len[u]-len[fail[u]])(slink[u])表示(u)一直沿着(fail)向上跳第一个结点(v),使得(diff[v] e diff[u])。用(g[x])维护(x)所在的等差数列的(dp)值的和,然后不断的跳(slink[x]),用(g[x])更新(dp[i])。对于每个(i)(slink)最多跳(log)次,时间复杂度为(nlogn)

    Code

    #include<bits/stdc++.h>
    #define mp make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,mid,p<<1
    #define rson mid+1,r,p<<1|1
    #define ll long long
    using namespace std;
    const int inf=1e9;
    const int mod=1e9+7;
    const int maxn=1e6+10;
    char s[maxn],t[maxn];
    int T,n,now;
    int dp[maxn],g[maxn];
    void add(int &x,int y){
        x+=y;
        if(x>mod) x-=mod;
    }
    struct PAM{
        int son[maxn][26],fail[maxn],len[maxn],dif[maxn],slink[maxn],tot,last;
        int newnode(int x){
            ++tot;
            for(int i=0;i<26;i++) son[tot][i]=0;
            fail[tot]=0;len[tot]=x;
            return tot;
        }
        void init(){
            tot=-1;newnode(0);newnode(-1);
            fail[0]=1;
            last=0;
        }
        int gao(int x){
            while(s[now-len[x]-1]!=s[now]) x=fail[x];
            return x;
        }
        void insert(){
            int p=gao(last);
            if(!son[p][s[now]-'a']){
                int tmp=son[gao(fail[p])][s[now]-'a'];
                son[p][s[now]-'a']=newnode(len[p]+2);
                fail[tot]=tmp;
                dif[tot]=len[tot]-len[tmp];
                if(dif[tot]==dif[fail[tot]]){
                    slink[tot]=slink[fail[tot]];
                }else{
                    slink[tot]=fail[tot];
                }
            }
            last=son[p][s[now]-'a'];
        }
        int solve(){
            for(now=1;now<=n;now++){
                insert();
                for(int x=last;x>1;x=slink[x]){
                    g[x]=dp[now-dif[x]-len[slink[x]]];
                    if(dif[x]==dif[fail[x]]) add(g[x],g[fail[x]]);
                    if(now%2==0) add(dp[now],g[x]);
                }
            }
            return dp[n];
        }
    }P;
    int main(){
        scanf("%s",t+1);
        n=strlen(t+1);
        P.init();
        dp[0]=1;
        for(int i=1,j=1;i<=n;i+=2,j++){
            s[i]=t[j];
            s[i+1]=t[n-j+1];
        }
        printf("%d
    ",P.solve());
        return 0;
    }
    
  • 相关阅读:
    常用数列
    sqrt
    树状数组
    hash
    P1102 A-B数对
    codevs 1795 金字塔 2
    P2296 寻找道路
    [USACO16JAN]子共七Subsequences Summing to Sevens
    P3397 地毯
    关于调用&&传址
  • 原文地址:https://www.cnblogs.com/xyq0220/p/14030567.html
Copyright © 2011-2022 走看看