• 一坨字符串难题


    CodeForces 204E Little Elephant and Strings

    http://codeforces.com/contest/204/problem/E

    输入n个字符串,由小写字母组成。

    对于每一个字符串,求出这个字符串,有多少个区间[L,R],使得子串L..R在至少K个字符串中出现,包括它本身。

    SAM竟有如此美妙的构造方法。

    首先用一个Trie来构造SAM。然后考虑par树,我们要求的是每个结点所代表的子串,包含了多少个字符串。

    如果沿着Trie上的结点对应的SAM结点来访问SAM的话,可以发现对于每个结点它以及它沿着par树上的结点都在Trie上出现过一次,将这个结点的访问次数加一,那么对par树用一遍dfs使cnt[u]+=cnt[v]似乎就可以求出所有结点的访问次数了。但是这样会有一个重复计数,两个结点的公共祖先以上的结点重复计数过了,因此把它们的公共结点访问次数减一就对了。用Tarjan做一遍离线的LCA可以解决,记录Trie对应的每个串所包含的点的当前的公共祖先,如果有一个新的结点出现,就处理旧的公共祖先与当前点的公共祖先。

    最后保留下所有出现次数>=k的结点。统计这个结点的len[u]-len[par[u]]即包含的子串数。我们通过Trie知道了某个结点是否是某个串的前缀,那么这个结点的后缀也应该在这个串上,统计par树上的父结点到当前结点的cnt,累加到该串的答案中。

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <queue>
      6 
      7 using namespace std;
      8 typedef long long LL;
      9 typedef vector<int> VI;
     10 typedef vector<int>::iterator Iter;
     11 const int maxn=210000;
     12 const int MAXS=26;
     13 char buf[maxn];
     14 LL ans[maxn];
     15 int TtoM[maxn],MtoT[maxn];
     16 int n,K;
     17 int cnt[maxn];
     18 namespace Trie{
     19     int trans[maxn][26];
     20     VI spb[maxn];
     21     int tot;
     22     int NewNode(){return tot++;}
     23     void Insert(char s[],int id){
     24         int u=0;
     25         for (int i=0;s[i];i++){
     26             int c=s[i]-'a';
     27             if (!trans[u][c]) trans[u][c]=NewNode();
     28             u=trans[u][c];
     29             spb[u].push_back(id);
     30         }
     31     }
     32     void Init(){
     33         tot=0;
     34         NewNode();
     35     }
     36 }
     37 
     38 namespace SAM{
     39     int trans[maxn][26],par[maxn],len[maxn],tot;
     40     VI adj[maxn];
     41     inline int NewNode(){
     42         memset(trans[tot],0,sizeof(trans[tot]));
     43         return tot++;
     44     }
     45     inline int NewNode(int u){
     46         memcpy(trans[tot],trans[u],sizeof(trans[u]));
     47         par[tot]=par[u];
     48         return tot++;
     49     }
     50     inline int h(int u){
     51         return len[u]-len[par[u]];
     52     }
     53     int Extend(int last,int w){
     54         int p=last,np=NewNode();
     55         len[np]=len[p]+1;
     56         while (p&&!trans[p][w]){
     57             trans[p][w]=np;
     58             p=par[p];
     59         }
     60         if (!p&&!trans[p][w]) {
     61             trans[p][w]=np;
     62             par[np]=0;
     63         }
     64         else{
     65             int q=trans[p][w];
     66             if (len[p]+1==len[q]) par[np]=q;
     67             else{
     68                 int nq=NewNode(q);
     69                 len[nq]=len[p]+1;
     70                 par[q]=par[np]=nq;
     71                 while (p&&trans[p][w]==q){
     72                     trans[p][w]=nq;
     73                     p=par[p];
     74                 }
     75                 if (!p&&trans[p][w]==q) trans[p][w]=nq;
     76             }
     77         }
     78         return np;
     79     }
     80     void Gao(){
     81         tot=0;
     82         queue<int>que;
     83         que.push(0);
     84         TtoM[0]=NewNode();
     85         while (que.size()){
     86             int u=que.front();
     87             que.pop();
     88             for (int w=0;w<26;w++){
     89                 int v=Trie::trans[u][w];
     90                 if (v){
     91                     TtoM[v]=Extend(TtoM[u],w);
     92                     MtoT[TtoM[v]]=v;
     93                     que.push(v);
     94                 }
     95             }
     96         }
     97         for (int i=1;i<tot;i++) adj[par[i]].push_back(i);
     98     }
     99     void Check(){
    100         for (int u=1;u<tot;u++){
    101             cnt[u]=cnt[u]>=K?h(u):0;
    102         }
    103     }
    104 }
    105 
    106 namespace Tarjan{
    107     int pa[maxn],r[maxn],a[maxn],l[maxn];
    108     void Make(int x){
    109         r[x] = 0;
    110         pa[x] = x;
    111         a[x] = x;
    112     }
    113     int Find(int x){
    114         if (x!=pa[x]) pa[x]=Find(pa[x]);
    115         return pa[x];
    116     }
    117     void Union(int _x, int _y){
    118         int x=Find(_x);
    119         int y=Find(_y);
    120         if (r[x]<r[y]) pa[y]=x;
    121         else{
    122             pa[x]=y;
    123             a[y]=_x;
    124             if (r[x]==r[y]) r[x]++;
    125         }
    126     }
    127     void Tarjan(int u=0){
    128         Make(u);
    129         for (Iter it=SAM::adj[u].begin();it!=SAM::adj[u].end();it++){
    130             Tarjan(*it);
    131             Union(u,*it);
    132         }
    133         if (MtoT[u]){
    134             for (Iter it=Trie::spb[MtoT[u]].begin();it!=Trie::spb[MtoT[u]].end();it++){
    135                 int v=*it;
    136                 --cnt[a[Find(l[v])]];
    137                 ++cnt[u];
    138                 l[v]=u;
    139 
    140             }
    141         }
    142     }
    143     void dfs1(int u=0){
    144         int sz=SAM::adj[u].size();
    145         for (int i=0;i<sz;i++){
    146             int v=SAM::adj[u][i];
    147             dfs1(v);
    148             cnt[u]+=cnt[v];
    149         }
    150     }
    151     void dfs2(int u=0){
    152         int sz=SAM::adj[u].size();
    153         for (int i=0;i<sz;i++){
    154             int v=SAM::adj[u][i];
    155             cnt[v]+=cnt[u];
    156             dfs2(v);
    157         }
    158         sz=Trie::spb[MtoT[u]].size();
    159         for (int i=0;i<sz;i++){
    160             int v=Trie::spb[MtoT[u]][i];
    161             ans[v]+=cnt[u];
    162         }
    163     }
    164     void Init(){
    165         memset(l,0,sizeof(l));
    166     }
    167 }
    168 int main()
    169 {
    170     scanf("%d%d",&n,&K);
    171     Trie::Init();
    172     for (int i=0;i<n;i++){
    173         scanf("%s",buf);
    174         Trie::Insert(buf,i);
    175     }
    176     SAM::Gao();
    177     Tarjan::Init();
    178     Tarjan::Tarjan();
    179     Tarjan::dfs1();
    180     SAM::Check();
    181     Tarjan::dfs2();
    182     for (int i=0;i<n;i++) printf("%I64d ",ans[i]);puts("");
    183     return 0;
    184 }
    View Code

    CodeForces 452E Three strings 

    http://codeforces.com/contest/452/problem/E

    有三个字符串s1、s2、s3,对于每一个l(1<=l<=min(|s1|,|s2|,|s3|)),问存在多少对(i1,i2,i3),使sk[ik... ik + l - 1](k = 1, 2, 3)相等,结果对109 + 7取模。

    将三个串用特殊符号隔开拼接在一起,关键点在于求出结点在三个串上的right集合。

    可以从根结点进行一个Dp来求出三个right集合。

    而有了right集合后,对于一个结点u代表的子串来说,它对于len[u]存在right[0]*right[1]*right[2]个三元对,使子串相等。

    注意如过一个状态表示的串出现了T次,那么该串的后缀也至少出现了T次,为了统计方便将num[len[par[u]]]减去num[len[u]],最后将num[i+1]累加到num[i]上即可。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 const int MOD=1e9+7;
      8 const int maxn=611111;
      9 typedef long long LL;
     10 LL num[maxn];
     11 namespace SAM{
     12     int trans[maxn][30],par[maxn],len[maxn],tot,last;
     13     LL cnt[maxn][3];
     14     inline int NewNode(){
     15         memset(trans[tot],0,sizeof(trans[tot]));
     16         return tot++;
     17     }
     18     inline int NewNode(int u){
     19         memcpy(trans[tot],trans[u],sizeof(trans[u]));
     20         par[tot]=par[u];
     21         return tot++;
     22     }
     23     inline int h(int u){
     24         return len[u]-len[par[u]];
     25     }
     26     void Extend(int w){
     27         int p=last,np=NewNode();
     28         len[np]=len[p]+1;
     29         while (p&&!trans[p][w]){
     30             trans[p][w]=np;
     31             p=par[p];
     32         }
     33         if (!p&&!trans[p][w]) {
     34             trans[p][w]=np;
     35             par[np]=0;
     36         }
     37         else{
     38             int q=trans[p][w];
     39             if (len[p]+1==len[q]) par[np]=q;
     40             else{
     41                 int nq=NewNode(q);
     42                 len[nq]=len[p]+1;
     43                 par[q]=par[np]=nq;
     44                 while (p&&trans[p][w]==q){
     45                     trans[p][w]=nq;
     46                     p=par[p];
     47                 }
     48                 if (!p&&trans[p][w]==q) trans[p][w]=nq;
     49             }
     50         }
     51         last=np;
     52     }
     53     bool vis[maxn];
     54     void Dp(int u){
     55         if (vis[u]) return;
     56         vis[u]=true;
     57         for (int k=0;k<3;k++){
     58             if (trans[u][26+k]) cnt[u][k]=1;
     59         }
     60         for (int i=0;i<26;i++){
     61             int v=trans[u][i];
     62             if (v){
     63                 Dp(v);
     64                 for (int k=0;k<3;k++){
     65                     cnt[u][k]=(cnt[u][k]+cnt[v][k])%MOD;
     66                 }
     67             }
     68         }
     69     }
     70     void Gao(){
     71         for (int i=1;i<tot;i++){
     72             LL tmp=((cnt[i][0]*cnt[i][1])%MOD*cnt[i][2])%MOD;
     73             num[len[i]]=(num[len[i]]+tmp)%MOD;
     74             num[len[par[i]]]=(num[len[par[i]]]-tmp+MOD)%MOD;
     75         }
     76         for (int i=tot-2;i>=1;i--){
     77             num[i]=(num[i]+num[i+1])%MOD;
     78         }
     79     }
     80     void Init(){
     81         memset(vis,0,sizeof(vis));
     82         memset(cnt,0,sizeof(cnt));
     83         tot=0;
     84         NewNode();
     85     }
     86     void Debug(int tp=0){
     87         if (tp==0)
     88         for (int i=0;i<tot;i++){
     89             printf("i=%d,par=%d,len=%d
    ",i,par[i],len[i]);
     90             for (int j=0;j<30;j++){
     91                 if (trans[i][j]){
     92                     printf("to %d %c
    ",trans[i][j],(char)(j+'a'));
     93                 }
     94             }
     95         }
     96         if (tp==1)
     97         for (int i=0;i<tot;i++){
     98             printf("i=%d %I64d %I64d %I64d
    ",i,cnt[i][0],cnt[i][1],cnt[i][2]);
     99         }
    100     }
    101 }
    102 const int INF=0x3f3f3f3f;
    103 char s[maxn];
    104 int main()
    105 {
    106     SAM::Init();
    107     int n=INF;
    108     scanf("%s",s);
    109     n=min(n,(int)strlen(s));
    110     for (int i=0;s[i];i++) SAM::Extend(s[i]-'a');
    111     SAM::Extend(26);
    112     scanf("%s",s);
    113     n=min(n,(int)strlen(s));
    114     for (int i=0;s[i];i++) SAM::Extend(s[i]-'a');
    115     SAM::Extend(27);
    116     scanf("%s",s);
    117     n=min(n,(int)strlen(s));
    118     for (int i=0;s[i];i++) SAM::Extend(s[i]-'a');
    119     SAM::Extend(28);
    120     SAM::Dp(0);
    121     //SAM::Debug(0);
    122     //SAM::Debug(1);
    123     SAM::Gao();
    124     for (int i=1;i<=n;i++){
    125         if (i>1) printf(" ");
    126         printf("%I64d",num[i]);
    127     }
    128     puts("");
    129     return 0;
    130 }
    View Code

    CodeForces 316G3 Good Substrings

    http://codeforces.com/contest/316/problem/G3

    统计一个字符串有多少个好的子串,好的子串是指,有n个规则(P,L,R),其中P是一个字符串,L与R是一个整数,如果串T在串P中出现的次数在[L,R]区间就称T满足规则。而满足所有规则的子串称为好的子串。

    HDU 4943 K-th good string

    http://acm.hdu.edu.cn/showproblem.php?pid=4943

    有一个字符串S,定义(x,p)为S[p-x+1,p-x+2,…,p]。

    有三种类型的信息:

    (x,p) 是好的,这里不包含(x,p)的子串。

    (x,p) 是不好的。

    (x,p)和整数k,回答第k个好串的长度。

    ACdream 1117 Suffix Automation

    http://acdream.info/problem?pid=1117

    给你一个字符串集合(包含若干个字符串),最多10w次询问。

    每次询问 i 串的a后缀跟 j 串的 b 后缀的最长的"特殊"公共前缀,这个公共前缀需要在字符串集合中出现。

  • 相关阅读:
    oracle数据库的隔离级别MS
    常用的oracle数据备份恢复方法有哪些?每一种的应用场景是什么?如果我的数据库是1T,说说你的备份 规划方案MS
    oracle中不能把字段类型改为clob,blob
    oracle dataguard中的常用视图(DG中常用视图)
    导出oracle awr 报告的操作
    mysql 部分命令
    企业微信HOOK逆向(sdk)——登录二维码api
    学习 游泳
    Celery Bo7
    算法时间复杂度
  • 原文地址:https://www.cnblogs.com/zinthos/p/3910595.html
Copyright © 2020-2023  润新知