【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?!
打了两种求拓扑序的方法。
贴一下代码。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#include<ctime>
#include<algorithm>
using namespace std; const int N=*,Mod=;
char s[N];
int n,sl,cl,ans,tot,last;
int son[N][],pre[N],step[N],sum[N],in[N],cnt[N],c[N];
bool vis[N];
queue<int> Q; int add_node(int x)
{
step[++tot]=x;
return tot;
} void extend(int ch)
{
int p=last,np=add_node(step[last]+);
while(p && !son[p][ch]) son[p][ch]=np,in[np]++,p=pre[p];
if(!p) pre[np]=;
else
{
int q=son[p][ch];
if(step[q]==step[p]+) pre[np]=q;
else
{
int nq=add_node(step[p]+);
memcpy(son[nq],son[q],sizeof(son[q]));
for(int i=;i<=;i++)
if(son[q][i]) in[son[q][i]]++;
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
while(son[p][ch]==q) in[q]--,in[nq]++,son[p][ch]=nq,p=pre[p];
}
}
last=np;
} void find_tp_1()
{
for(int i=;i<=tot;i++)
{
if(in[i]==)
{
for(int j=;j<=;j++)
{
int y=son[i][j];
if(!y) continue;
in[y]--;
}
}
}
while(!Q.empty()) Q.pop();
Q.push();vis[]=;cl=;
while(!Q.empty())
{
int x=Q.front();vis[x]=;c[++cl]=x;Q.pop();
for(int i=;i<=;i++)
{
int y=son[x][i];
if(!y) continue;
in[y]--;
if(!in[y] && !vis[y]) vis[y]=,Q.push(y);
}
}
} bool cmp(int x,int y){return step[x]<step[y];}
void find_tp_2()
{
cl=;
for(int i=;i<=tot;i++)
{
if(in[i] || i==) c[++cl]=i;
}
sort(c+,c++cl,cmp);
} void solve()
{
cnt[]=;
for(int i=;i<=cl;i++)
{
int x=c[i];
for(int j=;j<=;j++)
{
int y=son[x][j];
if(!y || (x== && j==)) continue;
cnt[y]=(cnt[y]+cnt[x])%Mod;
sum[y]=(sum[y]+(sum[x]*)%Mod+(j*cnt[x])%Mod)%Mod;
}
}
} int main()
{
freopen("a.in","r",stdin);
// freopen("me.out","w",stdout);
while(scanf("%d",&n)!=EOF)
{
memset(son,,sizeof(son));
memset(step,,sizeof(step));
memset(pre,,sizeof(pre));
memset(in,,sizeof(in));
memset(cnt,,sizeof(cnt));
memset(sum,,sizeof(sum));
tot=;add_node();last=;
for(int i=;i<=n;i++)
{
scanf("%s",s+);
sl=strlen(s+);
last=;
for(int j=;j<=sl;j++) extend(s[j]-'');
}
find_tp_1();//找拓扑序方法一 : bfs=拓扑排序
// find_tp_2();//方法二:直接对step[x]进行排序
solve();
ans=;
for(int i=;i<=tot;i++) ans=(ans+sum[i])%Mod;
printf("%d\n",ans);
// cout<<"Time Used : "<<(double)clock()/CLOCKS_PER_SEC<<" s."<<endl;
}
return ;
}
【hdu4436/LA6387-str2int】sam处理不同子串的更多相关文章
- 后缀自动机(SAM)
*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符 ...
- 后缀自己主动机(SAM)学习指南
*在学习后缀自己主动机之前须要熟练掌握WA自己主动机.RE自己主动机与TLE自己主动机* 什么是后缀自己主动机 后缀自己主动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂 ...
- 【算法】后缀自动机(SAM) 例题
算法介绍见:http://www.cnblogs.com/Sakits/p/8232402.html 广义SAM资料:https://www.cnblogs.com/phile/p/4511571.h ...
- hihoCoder 后缀自动机三·重复旋律6
后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...
- BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1017 Solved: 599[Submit][S ...
- 51nod1647 小Z的trie
题意:给你n个字符串,m次查询,每次问你第p个字符串的s到t的字符串在n个字符串建成的字典树上出现了多少次 题解:先建出字典树,在字典树上拓展sam,记录每个子串的出现次数.查询时只需找出在字典树上的 ...
- HihoCoder - 1445 后缀自动机 试水题
题意:求子串个数 SAM中每个子串包含于某一个状态中 对于不同的状态\(u,v\),\(sub(u)∩sub(v)=NULL\) 因此答案就是对于所有的状态\(st\),\(ans=\sum_{st} ...
- 解题:APIO 2014 回文串
题面 初见SAM 洛谷数据太弱了,我SAM写错了居然有90pts=.=??? SAM求一个子串$(l,r)$的出现次数:从右端点对应状态开始在parent树上倍增,当目标节点的$len$大于等于子串长 ...
- 【计蒜客】是男人就过 8 题--Pony.AI 题 A. A String Game 后缀自动机+SG函数
[题目]A. A String Game [题意]给定目标串S和n个子串Ti,Alice和Bob轮流选择一个子串操作,必须且只能在子串末尾添加一个字符使得新串也是S的子串,不能操作即输,求胜利者.|S ...
随机推荐
- 3、Java并发编程:Thread类的使用
Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...
- ubuntu下安装redis及在php中使用
一.安装redis sudo apt-get install redis-server 安装完成后,Redis服务器会自动启动,我们可以通过下面的命令行检查一下: # redis-cli > p ...
- 前端技术Jquery与Ajax使用总结
前端技术Jquery与Ajax使用总结 虽然主要是做的后端,但是由于有些时候也要写写前台的界面,因此也就学习了下Jquery和Ajax的一些知识,虽说此次写的这些对于前端大神来说有些班门弄斧的感觉,但 ...
- 【Luogu P4644】Cleaning Shifts
题目 给定 \(n\) 个区间 \([a_i, b_i]\), 花费为 \(c_i\), 求覆盖 \([L, R]\) 区间的所有整数的最小花费. \(0\le n \le 10^4, 0\le L, ...
- Linux-Shell脚本编程-学习-7-总结前面开启后面的学习
国庆前期后国庆回来也都比较忙,把书一放下,在那起来,就难了,发现好多都开始忘记了,今天好不容易硬着头片看来两章,算是马马虎虎的把前面的基础性质的只是看完了吧. 后面讲开始学习Shell编程的高级阶段, ...
- C++学习011-常用内存分配及释放函数
C++用有多种方法来分配及释放内存,下面是一些经常使用的内存分配及释放函数 现在我还是一个技术小白,一般用到也指示 new+delete 和 malloc和free 其他的也是在学习中看到,下面的文字 ...
- MySQL☞length函数
length(字符串/列名):求出该字符串/列名中字符的个数 格式: select length(列名) from 表名 如下图:
- Jmeter非GUI命令参数说明
查看帮助 -h, --help print usage information and exit 查看版本 -v, --version print the version information an ...
- PAT——甲级1012:The Best Rank(有坑)
1012 The Best Rank (25 point(s)) To evaluate the performance of our first year CS majored students, ...
- Z.XML-Cocos2d-x开发笔记
大家都在热火朝天的使用Cocos2d-x引擎做游戏开发,那么大家不妨把过程中解决的关键问题记录在这里,做一个分享! 1.在Android平台下打开网页 1.1修改项目工程源文件 在你的项目工程源文件中 ...