• 解题:NOI 2016 优秀的拆分


    题面

    其实题目不算很难,但是我调试的时候被玄学了,for循环里不写空格会RE,写了才能过。神**调了一个多小时是这么个不知道是什么的玩意(真事,可以问i207M=。=),心态爆炸

    发现我们只要找AA或者BB就行了,因为另一半反过来再做一次然后拼起来就可以了,那么就设$stp[i]$表示从$i$开始有多少个$AA$这样的串,$edp[i]$表示在$i$结束有多少个$AA$这样的串。一个个位置暴力求是$O(n^2)$的,可以得95pts(雾。

    AC做法是一种巧妙(套路?毕竟我做题少)的做法。枚举一个len把串分成长度为$len$的段,然后发现形如$AA$的字符串一定至少跨过了两个分界点,那么我们求一下这两个分界点的$LCP$和$LCS$,看看是不是超过$len$即可,然后具体的贡献可以用差分实现,时间复杂度$O(nlog n)$(不知道为啥$n$只出了30000,可能是为了放哈希+二分的$O(nlog^2 n)$过去?)。

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int N=30005,K=16;
      7 struct a
      8 {
      9     char str[N];
     10     int sec[N],bkt[N];
     11     int sar[N],rnk[N],hgt[N],st[N][K];
     12     int len,siz;
     13     void Set()
     14     {
     15         len=0,siz=30;
     16         memset(sec,0,sizeof sec);
     17         memset(rnk,0,sizeof rnk);
     18     }
     19     void Prework()
     20     {
     21         register int i;
     22         for(i=1;i<=len;i++)
     23             rnk[i]=str[i]-'a'+1,sec[i]=i;
     24     }
     25     void Basenum_Sort()
     26     {
     27         register int i;
     28         for(i=1;i<=siz;++i) bkt[i]=0;
     29         for(i=1;i<=len;++i) ++bkt[rnk[i]];
     30         for(i=1;i<=siz;++i) bkt[i]+=bkt[i-1];
     31         for(i=len;i>=1;--i) sar[bkt[rnk[sec[i]]]--]=sec[i];
     32     }   
     33     void Suffix_Sort()
     34     {
     35         register int i;
     36         int cnt=0,pw=1;
     37         Basenum_Sort();
     38         while(cnt<len)
     39         {
     40             cnt=0;
     41             for(i=1;i<=pw;i++) sec[++cnt]=len-pw+i;
     42             for(i=1;i<=len;i++) if(sar[i]>pw) sec[++cnt]=sar[i]-pw;
     43             Basenum_Sort(); swap(rnk,sec); rnk[sar[1]]=cnt=1;
     44             for(i=2;i<=len;i++)
     45                 cnt+=(sec[sar[i-1]]!=sec[sar[i]]||sec[sar[i-1]+pw]!=sec[sar[i]+pw]),rnk[sar[i]]=cnt;
     46             pw<<=1,siz=cnt;
     47         }
     48     }
     49     void Getting_Height()
     50     {
     51         register int i,p=0;
     52         for(i=1;i<=len;i++)
     53             if(rnk[i]!=1)
     54             {
     55                 int r=sar[rnk[i]-1];
     56                 while(str[r+p]==str[i+p]) p++;
     57                 hgt[rnk[i]]=p; if(p>0) p--; 
     58             }
     59         hgt[1]=0;
     60     }
     61     void Building_Table()
     62     {
     63         register int i,j;
     64         for(i=1;i<=len;i++)
     65             st[i][0]=hgt[i];
     66         int lgg=log2(len);
     67         for(i=1;i<=lgg;i++)
     68             for(j=1;j<=len-(1<<i)+1;j++)
     69                 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
     70     }
     71     int LCP_Query(int x,int y)
     72     {
     73         int xx=rnk[x],yy=rnk[y],lgg;
     74         if(xx>yy) swap(xx,yy); xx++,lgg=log2(yy-xx+1); 
     75         return min(st[xx][lgg],st[yy-(1<<lgg)+1][lgg]);
     76     }
     77 }SA[2];
     78 int n,lth,stp[N],edp[N];
     79 void Init()
     80 {
     81     SA[0].Set(),SA[1].Set();
     82     memset(stp,0,sizeof stp);
     83     memset(edp,0,sizeof edp);
     84 }
     85 int main()
     86 {
     87     register int i,j,k,h;
     88     scanf("%d",&n);
     89     for(i=1;i<=n;i++)
     90     {
     91         Init(); scanf("%s",SA[0].str+1);
     92         SA[0].len=SA[1].len=lth=strlen(SA[0].str+1);
     93         for(j=1;j<=lth;j++)
     94             SA[1].str[j]=SA[0].str[lth-j+1];
     95         for(j=0;j<=1;j++)
     96         {
     97             SA[j].Prework();
     98             SA[j].Suffix_Sort();
     99             SA[j].Getting_Height();
    100             SA[j].Building_Table();
    101         }
    102         for(j=1;j<=lth/2;j++)
    103         {
    104             for(k=j,h=2*j;h<=lth;k+=j,h+=j)
    105             {
    106                 int l1=min(SA[0].LCP_Query(k,h),j);
    107                 int l2=min(SA[1].LCP_Query(lth-k+1,lth-h+1),j);
    108                 if(l1+l2>j)
    109                 {
    110                     stp[k-l2+1]++,edp[h-l2+j]++;
    111                     stp[k+l1-j+1]--,edp[h+l1]--;
    112                 }
    113             }
    114         }
    115         long long ans=0;
    116         for(j=1;j<=lth;j++) 
    117             stp[j]+=stp[j-1],edp[j]+=edp[j-1];
    118         for(j=1;j<lth;j++)
    119             ans+=1ll*stp[j+1]*edp[j];
    120         printf("%lld
    ",ans);
    121     }
    122     return 0;
    123 }
    View Code

    Upd on 2019.3.16:用SAM搞过去了,然而因为常数原因被同样复杂度的SA踩了

    你问怎么做到同样复杂度?写个RMQ LCA就行了(我就因为写这个才学的RMQ LCA=。=)

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int N=60005,K=17;
      7 struct SAM
      8 {
      9     char str[N];
     10     int p[N],noww[N],goal[N];
     11     int dfn[N],idf[N],fir[2*N],st[N][K];
     12     int trs[N][26],fth[N],len[N],ndp[N];
     13     int lth,lst,tot,cnt,dfo,app;
     14     void Init()
     15     {
     16         cnt=dfo=app=0,tot=lst=1;
     17         memset(p,0,sizeof p);
     18         memset(fth,0,sizeof fth);
     19         memset(len,0,sizeof len);
     20         memset(trs,0,sizeof trs);
     21     }
     22     void Link(int f,int t)
     23     {
     24         noww[++cnt]=p[f];
     25         goal[cnt]=t,p[f]=cnt;
     26     }
     27     int Insert(int ch)
     28     {
     29         int nde=lst,newn=++tot; 
     30         lst=newn,len[newn]=len[nde]+1;
     31         while(nde&&!trs[nde][ch])
     32             trs[nde][ch]=newn,nde=fth[nde];
     33         if(!nde) fth[newn]=1;
     34         else 
     35         {
     36             int tran=trs[nde][ch];
     37             if(len[tran]==len[nde]+1)
     38                 fth[newn]=tran;
     39             else 
     40             {
     41                 int rnde=++tot; len[rnde]=len[nde]+1;
     42                 for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i];
     43                 fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde;
     44                 while(nde&&trs[nde][ch]==tran)
     45                     trs[nde][ch]=rnde,nde=fth[nde];
     46             }
     47         }
     48         return newn;
     49     }
     50     void DFS(int nde)
     51     {
     52         idf[dfn[nde]=++dfo]=nde;
     53         st[fir[nde]=++app][0]=dfo;
     54         for(int i=p[nde];i;i=noww[i])    
     55             DFS(goal[i]),st[++app][0]=dfn[nde];
     56     }
     57     int LCA(int x,int y)
     58     {
     59         x=fir[x],y=fir[y];
     60         if(x>y) swap(x,y);
     61         int l2=log2(y-x+1);
     62         return idf[min(st[x][l2],st[y-(1<<l2)+1][l2])];
     63     }
     64     void Create()
     65     {
     66         for(int i=1;i<=lth;i++)
     67             ndp[i]=Insert(str[i]-'a');
     68         for(int i=1;i<=tot;i++)
     69             Link(fth[i],i); DFS(1);
     70         for(int i=1;i<=16;i++)
     71             for(int j=1;j+(1<<i)-1<=app;j++)
     72                 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
     73     }
     74     int LCS(int x,int y)
     75     {
     76         int lca=LCA(ndp[x],ndp[y]);
     77         return len[lca];
     78     }
     79 }s[2];
     80 int n,m,stp[N],edp[N];
     81 void Init()
     82 {
     83     memset(stp,0,sizeof stp);
     84     memset(edp,0,sizeof edp);
     85 }
     86 int main()
     87 {
     88     register int i,j,k,h;
     89     scanf("%d",&n);
     90     for(i=1;i<=n;i++) 
     91     {
     92         Init(); scanf("%s",s[0].str+1);
     93         s[0].lth=s[1].lth=m=strlen(s[0].str+1);
     94         for(j=1;j<=m;j++) s[1].str[j]=s[0].str[m-j+1];
     95         s[0].Init(),s[0].Create();
     96         s[1].Init(),s[1].Create(); 
     97         for(j=1;j<=(m>>1);j++)
     98         {
     99             for(k=j,h=2*j;h<=m;k+=j,h+=j)
    100             {
    101                 int l1=min(s[0].LCS(k,h),j);
    102                 int l2=min(s[1].LCS(m-k+1,m-h+1),j);
    103                 if(l1+l2>j)
    104                 {
    105                     stp[k-l1+1]++,edp[h-l1+j]++;
    106                     stp[k+l2-j+1]--,edp[h+l2]--;
    107                 }
    108             }
    109         }
    110         long long ans=0;
    111         for(j=1;j<=m;j++) stp[j]+=stp[j-1],edp[j]+=edp[j-1];
    112         for(j=1;j<m;j++) ans+=1ll*stp[j+1]*edp[j];
    113         printf("%lld
    ",ans);
    114     }
    115     return 0;
    116 }
    View Code
  • 相关阅读:
    观后感
    用户故事排球教练助手
    本周工作量
    本周个人作业
    个人工作量
    个人作业
    产品计划总结
    典型用户和场景总结
    排球比赛计分规则
    PowerShell ISE:Windows Server 2008 R2默认不安装
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/10148244.html
Copyright © 2020-2023  润新知