CF906E Reverses PAM+border

题意:

戳这里

分析:

  • 暴力:

对于PAM的DP题目,可能需要将题目转化一下,将原串变为 \(s_1t_1s_2t_2\dots s_nt_n\) ,这样对于一个需要翻转的区间 \([i,j]\) 满足 \(s_i=t_j,s_{i+1}=t_{j-1}\) 即区间 \([i,j]\) 在新构造的串上是一个偶回文子串,题目转化为对新串求最小偶回文分割方案,建出SAM暴力DP,转移式 \(f[i]=\min \{f[i],f[j]+1且s[j:i]为回文串\}\),因为 \(PAM\) 的结构,所以 \(s[j:i]\)\(s[1:i]\) 的一个回文后缀所以跳 \(fail\) 就能找到所有的 \(j\),复杂度理论上界 \(O(n^2)\)

  • 正解

由于PAM的树高可以达到\(O(n)\),所以暴力跳 \(fail\) 是会被卡的,所以我们需要利用 PAM 的另一个结论,由于串 S 的所有回文后缀排序后可以分为 \(O(\log n)\) 个等差数列,所以我们可以对于每一个等差数列进行转移,复杂度\(O(n\log n)\)

tip:

要特判长度为 2 的回文串划分是不需要代价

代码:

#include<bits/stdc++.h>
#define inl inline
#define reg register

using namespace std;

namespace zzc
{
    const int maxn = 1e6+5;
    int m,n;
    int f[maxn],whe[maxn],lpos[maxn];
    char ch[maxn],a[maxn],b[maxn];

    namespace PAM
    {
        int tot,lst;
        int len[maxn],trans[maxn][26],fail[maxn],slink[maxn],dif[maxn];

        inl void init()
        {
            len[0]=0;len[1]=-1;
            fail[0]=1;fail[1]=-1;
            tot=1;lst=0;
        }

        inl int get_fail(int x,int l)
        {
            while(ch[l-len[x]-1]!=ch[l]) x=fail[x];
            return x;
        }

        inl void insert(int c,int l)
        {
            int p=get_fail(lst,l);
            if(!trans[p][c])
            {
                int cur=++tot;
                len[cur]=len[p]+2;
                int tmp=get_fail(fail[p],l);
                fail[cur]=trans[tmp][c];
                trans[p][c]=cur;
                dif[cur]=len[cur]-len[fail[cur]];
                if(dif[cur]==dif[fail[cur]]) slink[cur]=slink[fail[cur]];
                else slink[cur]=fail[cur];
            }
            lst=trans[p][c];
        }
    }
    using namespace PAM;

    void work()
    {
        scanf("%s",a+1);scanf("%s",b+1);n=strlen(a+1);
        for(reg int i=1;i<=n;i++) ch[++m]=a[i],ch[++m]=b[i];
        init();for(reg int i=1;i<=m;i++) f[i]=1e9;
        ch[0]=ch[m+1]=100;whe[0]=1;
        for(reg int i=1;i<=m;i++)
        {
            insert(ch[i]-'a',i);
            for(reg int x=lst;x;x=slink[x])
            {
                whe[x]=i-len[slink[x]]-dif[x];
                if(dif[fail[x]]==dif[x]&&f[whe[x]]>f[whe[fail[x]]]) whe[x]=whe[fail[x]];
                if(i%2==0&&f[i]>f[whe[x]]+1) f[i]=f[whe[x]]+1,lpos[i]=whe[x];
                if(i%2==0&&ch[i]==ch[i-1]&&f[i]>f[i-2]) f[i]=f[i-2],lpos[i]=i-2;
            }
        }
        if(f[m]>=1e9) 
        {
            puts("-1");
            return ;
        }
        printf("%d\n",f[m]);
        for(reg int x=m;x;x=lpos[x]) if(x-lpos[x]!=2) printf("%d %d\n",lpos[x]/2+1,x/2);
    }
}

int main()
{
    zzc::work();
    return 0;
}
posted @ 2021-02-22 10:05  youth518  阅读(104)  评论(0编辑  收藏  举报