【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\n",ans);
128         // cout<<"Time Used : "<<(double)clock()/CLOCKS_PER_SEC<<" s."<<endl;
129     }
130     return 0;
131 }
时间: 2024-10-20 18:33:36

【hdu4436/LA6387-str2int】sam处理不同子串的相关文章

后缀自动机(SAM)学习指南

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.

后缀自己主动机(SAM)学习指南

*在学习后缀自己主动机之前须要熟练掌握WA自己主动机.RE自己主动机与TLE自己主动机* 什么是后缀自己主动机 后缀自己主动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造.可以接受一个字符串全部后缀的自己主动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 能够用 SAM 轻松水过.由此 SAM 流行了起来. 一般来说.能用后缀自己主动机解决的问题都能够用后缀数组解决.可是后缀自己

后缀自动机(SAM)

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.

hihocoder #1449 : 后缀自动机三&#183;重复旋律6

#1449 : 后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对于所有的K的答案. 解题方法提示 × 解题方法提示 小Hi:上次我们已经学习了后缀自动机了,今天我们再来解决一个用到后缀自动机的问题. 小Ho:好!那我们开始吧! 小Hi:现在我们要对K

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1017  Solved: 599[Submit][Status][Discuss] Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有

hihoCoder 后缀自动机三&#183;重复旋律6

后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对于所有的K的答案. 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串S.字符串长度不超过 1000000. 输出 共Length(S)行,每行一个整数,表示答案. 样例输入 aab 样例输出

广义后缀自动机

1).自动机的介绍 首先我们先来介绍一下什么是自动机,有限状态自动机的功能是识别字符串,令一个自动机A,若他能识别字符串S,就记为A(S)=Ture,否则A(S)=False. 自动机由五个部分组成,alpha:字符集,state:状态集合,init:初始状态,end:结束状态集合,trans:状态转移函数. 令trans(s,ch)表示当前状态是s,在读入字符ch之后,所到达的状态.如果trans(s,ch)这个转移不存在,为了方便,设其为null,同时null只能转移到null.null表示

浙江财经大学第十四届程序设计竞赛题解

[题面pdf下载]链接: https://pan.baidu.com/s/1Eb16fHtNYMLrRk9QnXWa-g 密码: dwn8 [题目牛客网提交链接] [现场赛排名]链接: https://pan.baidu.com/s/1jfzH6-7BoPhEjnijGQK53w 密码: y669 感谢各位大佬的参赛.  由于命题人水平不高,而且之前没有命题经验,又是第一次把题目放到外网,所以可能会有数据不严谨的情况出现:也有可能出题人对问题理解不深刻,没想到最优解.如果发现了题目中的各种问题,

HihoCoder - 1445 后缀自动机 试水题

题意:求子串个数 SAM中每个子串包含于某一个状态中 对于不同的状态\(u,v\),\(sub(u)∩sub(v)=NULL\) 因此答案就是对于所有的状态\(st\),\(ans=\sum_{st} maxlen(st)-minlen(st)+1\) #include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++) #define rrep(i,j,k) for(int i=j;i>=k;i--) #define p