【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 ...
随机推荐
- Dos命令%date:~0,10%
在使用命令对数据库备份的时候,想让备份的文件以当天的日期命名.需要获取当天的日期,获取当天的日期用date命令,获取当天的时间用time命令.但时间和日期一般都是有一定格式的,而使用的时候,是不想用那 ...
- jmeter使用beanshell构造参数化
1.先在本地写一个java类,用来随机生成一个数字,如: package com.jmeter.test; public class BeanShellTest { public int getRan ...
- html5判断设备的动作
相应的事件 deviceorientation事件提供设备的物理方向信息,表示为一系列本地坐标系的旋角. devicemotion事件提供设备的加速信息,表示为定义在设备上的坐标系中的卡尔迪坐标.其还 ...
- Z.XML第一次迭代分数分配
紧张的第一次迭代落下帷幕,便到了分数分配这样令人揪心又无奈的日子.如何进行分数分配,以使大家都能满意,这一直是个难以非常好地处理的问题.幸运地是,我们团队的所有成员每个人都对本次迭代乃至整个项目过程付 ...
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...
- java--List转换成json格式
方法一 首先导入jar包,json-rpc-1.0.jar public class List2Json { public static JSONArray ProLogList2Json(List& ...
- JVM(1)——简介
网上流传着一段挺有意思的话-- 对于从事C或C++的开发人员来说,他们既是内存管理的最高权力的皇帝,也是最基础的劳动人民,担负着每一个对象生命开始到终结的维护工作,有点光杆司令的赶脚. 但对于java ...
- Python数据分析(四)DataFrame, Series, ndarray, list, dict, tuple的相互转换
转自:https://blog.csdn.net/lambsnow/article/details/78517340 import numpy as np import pandas as pd ## ...
- arc073 F many moves(dp + 线段树)
设dp[i][y]表示一个点在x[i],另一个点在y时最小要走的步数 那么有以下转移 对于y != x[i-1]的状态,可以证明,他们直接加|x[i] - x[i-1]|即可(如果有其他方案,不符合对 ...
- 工具——代码中自动生成SVN版本号
本节和大家讨论一下程序集版本最后一位使用SVN版本号的自动生成方法,这里就向大家简单介绍一下.在进行自动部署的时候,经常需要用脚本获取程序的最新版本号.现在我们定义每个程序集的版本信息的最末段表示SV ...