• [luogu3785]文本校正


    约定:以下字符串下标从1开始

    定义$s$为偶回文串,当且仅当$s$的长度为偶数且$s$为回文串

    假设$s=ABC$,考虑$t$的情况,即$ABC$的全排列——

    1.$t=ABC$,即$s=t$,由于$nge 3$,随便划分即可

    2.$t=BCA$或$t=CAB$,即将$s$旋转后变为$t$,枚举$|A|$和$|AB|$(或$|BC|$和$|C|$)并哈希判定即可

    (注意最后划分要求非空,需要对旋转的位置分类讨论)

    3.$t=ACB$或$t=BAC$或$t=CBA$,枚举其中某一段并直接比较或哈希(第3类)来判定是否相等,剩下可以看作一个划分为两段的子问题

    更具体的,即判定是否存在$AB$使得$s=AB$且$t=BA$

    (为了方便,这里认为$s e t$,否则显然之前已经得到答案)

    记$l=|s|=|t|$,$l_{A}=max_{1le i<l,s[1,i]=t(l-i,l]}i$,$l_{B}$类似(即$|B|$的最大值)

    结论:若存在$AB$,则存在$AB$满足$|A|=l_{A}$或$|B|=l_{B}$

    构造字符串$P=s_{1}t_{l}s_{2}t_{l-1}...s_{n}t_{1}$,实际上就是将$P$划分为两个偶回文串

    上面所述的$l_{A}$和$l_{B}$,也即$P$最长为偶回文串的前缀和后缀(长度的一半)

    考虑一个命题,即:假设$P=x_{1}x_{2}=y_{1}y_{2}=z_{1}z_{2}$,并满足$|x_{1}|<|y_{1}|<|z_{1}|$且$x_{2},y_{1},y_{2},z_{1}$都是偶回文串,求证$x_{1}$和$z_{2}$是偶回文串

    若能证明上述命题,取$x_{1}x_{2}$为$|B|=l_{B}$的划分,$z_{1}z_{2}$为$|A|=l_{A}$的划分,$y_{1}y_{2}$为任意合法划分,$|y_{1}|=|x_{1}|$或$|z_{1}|$即直接成立,$|x_{1}|>|z_{1}|$即$l_{A}+l_{B}<l$显然无解,否则即可证明$x_{1}x_{2}$和$y_{1}y_{2}$都合法

    下面,来证明此命题——

    令$v=P(|y_{1}|,|z_{1}|]$,根据$y_{2}$回文和$x_{2}$回文,可得$v=P(2l-|v|,2l]=P(|x_{1}|,|x_{1}|+|v|]$

    另一方面,根据$y_{1}$和$z_{1}$回文,可得$forall 1le ile |y_{1}|,P_{i}=P_{|y_{1}|-i+1}=P_{i+|v|}$

    下面考虑结论(不妨仅考虑$x_{1}$),即求证$forall 1le ile |x_{1}|,P_{i}=P_{|x_{1}|-i+1}$,将两者都在$v$中表示:

    对于前者,令$i_{1}=i$,并将其不断加上$|v|$直至$i_{1}in (|x_{1}|,|x_{1}|+|v|]$,最终即等于$v_{i_{1}-|x_{1}|}$

    对于后者,根据$z_{1}$回文,可得$P_{|x_{1}|-i+1}=P_{|z_{1}|-|x_{1}|+i}$,令$i_{2}=|z_{1}|-|x_{1}|+i$,同样将其不断加上$|v|$直至$i_{2}in (y_{1},z_{1}]$,最终即等于$v_{i_{2}-|y_{1}|}$

    问题即求证$i_{1}-|x_{1}|=i_{2}-|y_{1}|$,也即$i-|x_{1}|equiv |z_{1}|-|x_{1}|+i-|y_{1}|(mod |v|)$,显然成立

    综上所述,只需要判定$|A|=l_{A}$和$|B|=l_{B}$的情况,具体判定可以用哈希,问题即变为求$l_{A}$和$l_{B}$

    由于问题需要更细化,再对$ABC$的排列情况分类讨论——

    (1)$t=ACB$或$t=BAC$(以下仅考虑前者),此时是枚举$|A|$,之后剩下的是$s$和$t$的一个后缀

    再以求$l_{A}$为例,即求$s$从$|A|+1$开始,最长的串使得其是$t$的后缀,那么将$t$接到$s$后面,也就是一个后缀的(最长)border长度,翻转后即求前缀的border长度,KMP即可

    (2)$t=CBA$,此时是枚举$|A|$并哈希判定,之后剩下的是$s$的一个后缀和$t$的一个前缀

    这个问题中,$l_{A}$和$l_{B}$就不同了,下面分类讨论:

    1.对于$l_{B}$,预处理出来所有可行的,并找到第一个小于等于此长度的(利用单调性可以做到线性)

    2.对于$l_{A}$,考虑前面证明时的构造,即令$P=s_{1}t_{n}s_{2}t_{n-1}...s_{n}t_{1}$(这里的$s$和$t$指最初的$s$和$t$),对于$l_{A}$即求从$i$开始的最长偶回文串(长度),使用manacher即可

    下面将讲述manacher做法——

    定义$d_{i}=max_{0le jle min(i,2l-i),s(i-j,i+j]为回文串}j$,即以$i$和$i+1$为中心的最长偶回文串(长度的一半),显然这个长度具有单调性(即满足条件的$j$是从0开始的连续区间)

    考虑求$d_{i}$,维护区间$[l,r]$,其中$r=max_{1le j<i}j+d_{j}$,$l$为对应此$r$的最小的$j$时的$j-d_{j}+1$

    若$i<r$,考虑$j=l+r-i-1$,根据$s[l,r]$为回文串,有$s[l,2j-l+1]$与$s(2i-r,r]$两者互为翻转的结果,其中前者以$j$和$j+1$为中心,后者以$i$和$i+1$为中心

    注意到$s$是回文串则将$s$翻转后也为回文串,因此$d_{i}ge max(d_{j},j-l+1)$,此时对$d_{j}$分类讨论:

    1.$d_{j}<j-l+1$,则$d_{i}=d_{j}$(如果再增大,即$d_{j}$也能增大)

    2.$d_{i}ge j-l+1$,则令$d_{i}=j-l+1$,并暴力增大$d_{i}$扩展

    若$i>r$,则令$d_{i}=0$,并暴力增大$d_{i}$扩展

    最后,再用$(j-d_{j},j+d_{j}]$去更新$[l,r]$(当$r<j+d_{j}$时)

    (特别的,初始状态设置为$l=1$和$r=0$,从$i=1$开始)

    关于这一做法的正确性显然,考虑时间复杂度:对于两个暴力增大$d_{i}$扩展的情况,都是初始$i+d_{i}=r$,之后不断增加$d_{i}$,最终仍令$r=i+d_{i}$

    (关于$ile r$的第2种情况,代入$j$的式子即可)

    换言之,每一次增加$d_{i}$,不妨同时令$r$增加1,那么显然总复杂度为$o(n)$

    (上面的manacher仅仅是对偶数部分,当然奇数部分也是类似的,但本题中只需要偶数即可)

    接下来,求出以$i$为起点的最长偶回文串,即找到最大的$j$满足$j-d_{j}<i$,答案即$j-i+1$,显然用单调队列维护即可,可以做到线性

    最终,总复杂度为$o(n)$,可以通过

    (另外此题在loj上似乎有一些问题,可以在洛谷上提交)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 1000005
      4 #define base 1000007
      5 #define mod 998244353
      6 int t,n,m,a[N],b[N],mi[N],suma[N],sumb[N],c[N<<1],nex[N<<1],d[N<<1];
      7 char ans[N][3];
      8 int read(){
      9     int x=0;
     10     char c=getchar();
     11     while ((c<'0')||(c>'9'))c=getchar();
     12     while ((c>='0')&&(c<='9')){
     13         x=x*10+c-'0';
     14         c=getchar();
     15     }
     16     return x;
     17 }
     18 int hasha(int l,int r){
     19     return (suma[r]-1LL*mi[r-l+1]*suma[l-1]%mod+mod)%mod;
     20 }
     21 int hashb(int l,int r){
     22     return (sumb[r]-1LL*mi[r-l+1]*sumb[l-1]%mod+mod)%mod;
     23 }
     24 int main(){
     25     mi[0]=1;
     26     for(int i=1;i<N;i++)mi[i]=1LL*mi[i-1]*base%mod;
     27     t=read();
     28     while (t--){
     29         n=read(),read();
     30         for(int i=1;i<=n;i++)a[i]=read();
     31         for(int i=1;i<=n;i++)b[i]=read();
     32         for(int i=1;i<=n;i++)suma[i]=(1LL*suma[i-1]*base+a[i])%mod;
     33         for(int i=1;i<=n;i++)sumb[i]=(1LL*sumb[i-1]*base+b[i])%mod;
     34         if (hasha(1,n)==hashb(1,n)){
     35             printf("YES
    1 1
    2 2
    3 %d
    ",n);
     36             continue;
     37         }
     38         bool flag=0;
     39         for(int i=1;i<n;i++)
     40             if ((hasha(1,n-i)==hashb(i+1,n))&&(hasha(n-i+1,n)==hashb(1,i))){
     41                 if (i>1)printf("YES
    %d %d
    1 1
    2 %d
    ",i+1,n,i);
     42                 else printf("YES
    %d %d
    %d %d
    1 %d
    ",i+1,i+1,i+2,n,i);
     43                 flag=1;
     44                 break;
     45             }
     46         if (flag)continue;
     47         for(int i=0;i<n;i++){
     48             c[i]=a[i+1];
     49             c[i+n]=b[i+1];
     50         }
     51         for(int i=0;i<n;i++)swap(c[i],c[2*n-i-1]);
     52         nex[0]=nex[1]=0;
     53         for(int i=1,j=0;i<2*n;i++){
     54             while ((j)&&(c[j]!=c[i]))j=nex[j];
     55             if (c[j]==c[i])j++;
     56             nex[i+1]=j;
     57         }
     58         for(int i=1;(i<=n)&&(a[i]==b[i]);i++){
     59             int l=nex[2*n-i];
     60             if ((l)&&(hasha(i+l+1,n)==hashb(i+1,n-l))){
     61                 printf("YES
    1 %d
    %d %d
    %d %d
    ",i,n-l+1,n,i+1,n-l);
     62                 flag=1;
     63                 break;
     64             }
     65         }
     66         if (flag)continue;
     67         for(int i=0;i<n;i++){
     68             c[i]=b[i+1];
     69             c[i+n]=a[i+1];
     70         }
     71         for(int i=0;i<n;i++)swap(c[i],c[2*n-i-1]);
     72         nex[0]=nex[1]=0;
     73         for(int i=1,j=0;i<2*n;i++){
     74             while ((j)&&(c[j]!=c[i]))j=nex[j];
     75             if (c[j]==c[i])j++;
     76             nex[i+1]=j;
     77         }
     78         for(int i=1;(i<=n)&&(a[i]==b[i]);i++){
     79             int l=nex[2*n-i];
     80             if ((l)&&(hasha(i+1,n-l)==hashb(i+l+1,n))){
     81                 printf("YES
    1 %d
    %d %d
    %d %d
    ",i,i+l+1,n,i+1,i+l);
     82                 flag=1;
     83                 break;
     84             }
     85         }
     86         if (flag)continue;
     87         for(int i=0;i<n;i++){
     88             c[i]=a[i+1];
     89             c[i+n]=b[i+1];
     90         }
     91         nex[0]=nex[1]=0;
     92         for(int i=1,j=0;i<2*n;i++){
     93             while ((j)&&(c[j]!=c[i]))j=nex[j];
     94             if (c[j]==c[i])j++;
     95             nex[i+1]=j;
     96         }
     97         for(int i=n;(i)&&(a[i]==b[i]);i--){
     98             int l=nex[n+i-1];
     99             if ((l)&&(hasha(l+1,i-1)==hashb(1,i-l-1))){
    100                 printf("YES
    %d %d
    1 %d
    %d %d
    ",i-l,i-1,i-l-1,i,n);
    101                 flag=1;
    102                 break;
    103             }
    104         }
    105         if (flag)continue;
    106         for(int i=0;i<n;i++){
    107             c[i]=b[i+1];
    108             c[i+n]=a[i+1];
    109         }
    110         nex[0]=nex[1]=0;
    111         for(int i=1,j=0;i<2*n;i++){
    112             while ((j)&&(c[j]!=c[i]))j=nex[j];
    113             if (c[j]==c[i])j++;
    114             nex[i+1]=j;
    115         }
    116         for(int i=n;(i)&&(a[i]==b[i]);i--){
    117             int l=nex[n+i-1];
    118             if ((l)&&(hasha(1,i-l-1)==hashb(l+1,i-1))){
    119                 printf("YES
    %d %d
    1 %d
    %d %d
    ",l+1,i-1,l,i,n);
    120                 flag=1;
    121                 break;
    122             }
    123         }
    124         if (flag)continue;
    125         c[0]=0;
    126         for(int i=n;i;i--)
    127             if (hasha(i,n)==hashb(1,n-i+1))c[++c[0]]=i;
    128         for(int i=1;i<=n;i++)
    129             if (hasha(1,i)==hashb(n-i+1,n)){
    130                 while ((c[0])&&(c[c[0]]<=i))c[0]--;
    131                 int l=c[c[0]];
    132                 if ((l)&&(hasha(i+1,l-1)==hashb(n-l+2,n-i))){
    133                     printf("YES
    %d %d
    %d %d
    1 %d
    ",n-i+1,n,n-l+2,n-i,n-l+1);
    134                     flag=1;
    135                     break;
    136                 }
    137             }
    138         if (flag)continue;
    139         for(int i=1;i<=n;i++){
    140             c[2*i-1]=a[i];
    141             c[2*i]=b[n-i+1];
    142         }
    143         int l=1,r=0;
    144         for(int i=1;i<=2*n;i++){
    145             if (i<r){
    146                 int j=l+r-i-1;
    147                 if (d[j]<j-l+1)d[i]=d[j];
    148                 else{
    149                     d[i]=j-l+1;
    150                     while ((i-d[i]>0)&&(i+d[i]<2*n)&&(c[i-d[i]]==c[i+d[i]+1]))d[i]++;
    151                 }
    152             }
    153             else{
    154                 d[i]=0;
    155                 while ((i-d[i]>0)&&(i+d[i]<2*n)&&(c[i-d[i]]==c[i+d[i]+1]))d[i]++;
    156             }
    157             if (i+d[i]>r){
    158                 l=i-d[i]+1;
    159                 r=i+d[i];
    160             }
    161         }
    162         int x=1,y=0;
    163         for(int i=2*n;i;i--){
    164             while ((x<=y)&&(c[x]-d[c[x]]>=i))x++;
    165             if (x>y)nex[i]=0;
    166             else nex[i]=c[x]-i+1;
    167             if ((x>y)||(c[y]-d[c[y]]>i-d[i]))c[++y]=i;
    168         }
    169         for(int i=1;i<=n;i++)
    170             if (hasha(1,i)==hashb(n-i+1,n)){
    171                 int l=nex[2*i+1];
    172                 if ((l)&&(hasha(i+l+1,n)==hashb(1,n-i-l))){
    173                     printf("YES
    %d %d
    %d %d
    1 %d
    ",n-i+1,n,n-i-l+1,n-i,n-i-l);
    174                     flag=1;
    175                     break;
    176                 }
    177             }
    178         if (!flag)printf("NO
    ");
    179     }
    180     return 0;
    181 }
    View Code
  • 相关阅读:
    Windows 10 版本 1507 中的新 AppLocker 功能
    github 查询
    Facebook Paper使用的第三方库
    C#如何使用右下角托盘图标notifyIcon
    C#如何设置窗体不能修改大小
    C#如何让Listbox支持多选
    C#如何开发多语言支持的Winform程序
    C#如何发布项目 发布软件
    C#如何编辑tab选项卡
    C#如何把写好的类编译成dll文件
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14790288.html
Copyright © 2020-2023  润新知