• 【hdu4436/LA6387-str2int】sam处理不同子串


    题意:给出n个数字,数字很长,用字符串读入,长度总和为10^5。求这n个字符串的所有子串(不重复)的和取模2012 。

    例如字符串101,和就是1+10+101=112。

    题解:

    就是求不同的子串连成一个数。
    sam的拓扑序真的很有用!按拓扑序可以保证能转移到当前x的节点都在之前被更新了。
    每个节点x维护cnt表示root到x的方案数,sum表示以x为结尾的子串和。
    找拓扑序有两种方法:1.拓扑排序一样bfs(O(n)) 2.按照step[x]排序(若x有个孩子是y,step[x]<=step[y](O(nlogn))
    按照拓扑序for一遍,对于x,它的孩子y,cnt[y]+=cnt[x],sum[y]+=sum[x]*10+cnt[x]*(y所代表的数字)。
    不能有前缀0----->根节点不走0孩子。
    节点数开了10^6才AC。tell me why?!

    打了两种求拓扑序的方法。

    贴一下代码。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<queue>
      6 #include<ctime>
      7 #include<algorithm>
      8 using namespace std;
      9 
     10 const int N=10*100010,Mod=2012;
     11 char s[N];
     12 int n,sl,cl,ans,tot,last;
     13 int son[N][30],pre[N],step[N],sum[N],in[N],cnt[N],c[N];
     14 bool vis[N];
     15 queue<int> Q;
     16 
     17 int add_node(int x)
     18 {
     19     step[++tot]=x;
     20     return tot;
     21 }
     22 
     23 void extend(int ch)
     24 {
     25     int p=last,np=add_node(step[last]+1);
     26     while(p && !son[p][ch]) son[p][ch]=np,in[np]++,p=pre[p];
     27     if(!p) pre[np]=1;
     28     else
     29     {
     30         int q=son[p][ch];
     31         if(step[q]==step[p]+1) pre[np]=q;
     32         else
     33         {
     34             int nq=add_node(step[p]+1);
     35             memcpy(son[nq],son[q],sizeof(son[q]));
     36             for(int i=0;i<=9;i++) 
     37                 if(son[q][i]) in[son[q][i]]++;
     38             pre[nq]=pre[q];
     39             pre[np]=pre[q]=nq;
     40             while(son[p][ch]==q) in[q]--,in[nq]++,son[p][ch]=nq,p=pre[p];
     41         }
     42     }
     43     last=np;
     44 }
     45 
     46 void find_tp_1()
     47 {
     48     for(int i=2;i<=tot;i++)
     49     {
     50         if(in[i]==0)
     51         {
     52             for(int j=0;j<=9;j++)
     53             {
     54                 int y=son[i][j];
     55                 if(!y) continue;
     56                 in[y]--;
     57             }
     58         }
     59     }
     60     while(!Q.empty()) Q.pop();
     61     Q.push(1);vis[1]=1;cl=0;
     62     while(!Q.empty())
     63     {
     64         int x=Q.front();vis[x]=0;c[++cl]=x;Q.pop();
     65         for(int i=0;i<=9;i++)
     66         {
     67             int y=son[x][i];
     68             if(!y) continue;
     69             in[y]--;
     70             if(!in[y] && !vis[y]) vis[y]=1,Q.push(y); 
     71         }
     72     }
     73 }
     74 
     75 bool cmp(int x,int y){return step[x]<step[y];}
     76 void find_tp_2()
     77 {
     78     cl=0;
     79     for(int i=1;i<=tot;i++)
     80     {
     81         if(in[i] || i==1) c[++cl]=i;
     82     }
     83     sort(c+1,c+1+cl,cmp);
     84 }
     85 
     86 void solve()
     87 {
     88     cnt[1]=1;
     89     for(int i=1;i<=cl;i++)
     90     {
     91         int x=c[i];
     92         for(int j=0;j<=9;j++)
     93         {
     94             int y=son[x][j];
     95             if(!y || (x==1 && j==0)) continue;
     96             cnt[y]=(cnt[y]+cnt[x])%Mod;
     97             sum[y]=(sum[y]+(sum[x]*10)%Mod+(j*cnt[x])%Mod)%Mod;
     98         }
     99     }
    100 }
    101 
    102 int main()
    103 {
    104     freopen("a.in","r",stdin);
    105     // freopen("me.out","w",stdout);
    106     while(scanf("%d",&n)!=EOF)
    107     {
    108         memset(son,0,sizeof(son));
    109         memset(step,0,sizeof(step));
    110         memset(pre,0,sizeof(pre));
    111         memset(in,0,sizeof(in));
    112         memset(cnt,0,sizeof(cnt));
    113         memset(sum,0,sizeof(sum));
    114         tot=0;add_node(0);last=1;
    115         for(int i=1;i<=n;i++) 
    116         {
    117             scanf("%s",s+1);
    118             sl=strlen(s+1);
    119             last=1;
    120             for(int j=1;j<=sl;j++)     extend(s[j]-'0');
    121         }
    122         find_tp_1();//找拓扑序方法一 : bfs=拓扑排序
    123         // find_tp_2();//方法二:直接对step[x]进行排序
    124         solve();
    125         ans=0;
    126         for(int i=1;i<=tot;i++) ans=(ans+sum[i])%Mod;
    127         printf("%d
    ",ans);
    128         // cout<<"Time Used : "<<(double)clock()/CLOCKS_PER_SEC<<" s."<<endl;
    129     }
    130     return 0;
    131 }
  • 相关阅读:
    洛谷 P2197 nim游戏
    洛谷 P1168 中位数
    第十一次发博不知道用什么标题好
    第十次发博不知道用什么标题好
    第九次发博不知道用什么标题好
    第八次发博不知道用什么标题好
    第七次发博不知道用什么标题好
    第六次发博不知道用什么标题好
    第五次发博不知道用什么标题好
    第四次发博不知道用什么标题好
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5840263.html
Copyright © 2020-2023  润新知