zoukankan      html  css  js  c++  java
  • bzoj4566 / P3181 [HAOI2016]找相同字符

    P3181 [HAOI2016]找相同字符

    后缀自动机
    (正解应是广义后缀自动机
    并不会广义后缀自动机。
    然鹅可以用普通的后缀自动机。
     
    我们先引入一个问题:算出从一个串内取任意两个不重合子串完全相同的方案数。
    显然,对于每个点$w$,$tot+=siz[w]*(siz[w]-1)/2*(len[w]-len[fa[w]])$
    $siz[w]$表示该点对应子串出现次数
    那么答案即为$tot_{a+b}-tot_a-tot_b$
    计算$tot_{a+b}$时在$a,b$间插入一个特殊字符即可。(插入$'{'='z'+1$较方便)
    attention:数组需要开n*2*2=800000大小!
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define N 800005
     6 int n; char s1[N],s2[N];
     7 long long ans,tot;
     8 struct Sam{
     9     int nxt[N][27],len[N],siz[N],fa[N];
    10     int p,q,last,ed,a[N],c[N];
    11     void clear(){
    12         last=ed=1;
    13         memset(fa,0,sizeof(fa));
    14         memset(nxt,0,sizeof(nxt));
    15         memset(len,0,sizeof(len));
    16         memset(siz,0,sizeof(siz));
    17         memset(c,0,sizeof(c));
    18     }
    19     void add(int c){
    20         p=last; len[last=++ed]=len[p]+1; siz[ed]=1;
    21         for(;p&&!nxt[p][c];p=fa[p]) nxt[p][c]=ed;
    22         if(!p){fa[ed]=1; return;}
    23         q=nxt[p][c];
    24         if(len[q]==len[p]+1){fa[ed]=q; return;}
    25         len[++ed]=len[p]+1;
    26         memcpy(nxt[ed],nxt[q],sizeof(nxt[q]));
    27         fa[ed]=fa[q]; fa[q]=fa[ed-1]=ed;
    28         for(;nxt[p][c]==q;p=fa[p]) nxt[p][c]=ed;
    29     }//裸的板子
    30     void calc(){
    31         for(int i=1;i<=ed;++i) ++c[len[i]];
    32         for(int i=1;i<=ed;++i) c[i]+=c[i-1];
    33         for(int i=1;i<=ed;++i) a[c[len[i]]--]=i;//对len进行排序代替dfs
    34         for(int i=ed;i;--i){
    35             int w=a[i]; siz[fa[w]]+=siz[w];
    36             tot+=1ll*siz[w]*(siz[w]-1)/2*(len[w]-len[fa[w]]);//累计每个点的贡献
    37         }
    38     }
    39 }sam;
    40 void solve(char *v,int x){
    41     tot=0; n=strlen(v+1); sam.clear();
    42     for(int i=1;i<=n;++i) sam.add(v[i]-'a');
    43     sam.calc(); ans+=tot*x;
    44 }
    45 int main(){
    46     scanf("%s",s1+1); scanf("%s",s2+1);
    47     solve(s1,-1); solve(s2,-1);
    48     strcat(s1+1,"{"); strcat(s1+1,s2+1);
    49     solve(s1,1); printf("%lld",ans);
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    记录此刻的感受(2018年8月26日19:44)
    提高工作效率
    VS C++项目报错warning C4199: ……use /Zc:twoPhase-
    dll加载遇到的问题
    记录xerces使用(VS2017 C++)
    vs编译应用程序不依赖运行vs环境
    [Locked] Binary Tree Vertical Order Traversal
    [Locked] Group Shifted Strings
    [Locked] Graph Valid Tree
    [Locked] Flatten 2D Vector
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10223177.html
Copyright © 2011-2022 走看看