HDU_1457_后缀自动机四·重复旋律7
#1457 : 后缀自动机四·重复旋律7
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。
神奇的是小Hi发现了一部名字叫《十进制进行曲大全》的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字。
现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0)。答案有可能很大,我们需要对(10^9 + 7)取摸。
输入
第一行,一个整数N,表示有N部作品。
接下来N行,每行包含一个由数字0-9构成的字符串S。
所有字符串长度和不超过 1000000。
输出
共一行,一个整数,表示答案 mod (10^9 + 7)。
- 样例输入
-
2
101
09 - 样例输出
-
131
- 给出n个数串然后求出所有数串中所有子数串的sum
- 如果一个一个的字串来求就要造n个自动机
- 至于计算过程就是对于每一个节点延伸到下一个节点过程中将当前sum乘10之后加上到下一个节点的单个数乘以当前字串出现次数的乘积即可
- 那么这样的计算方式没有问题但是建立n个SAM耗时太长了
- 那么我们可不可以减少SAM的建立呢?
- 还是可以的,只要把全部的字串用“:”链接,之后再建立SAM即可
- 在这里我们总的计算方式是不变的
- 但是对于一个出现过“:”的字串是不应该进行计算的,因为如果出现“:”就代表着当前字串包含至少两个原始串
- 所以我们现在的问题是怎样辨别当前字串中是否出现过“:”
- 我们可以通过在字串出现次数这里做文章,对于字串中出现“:”的我们可以通过把字串出现次数标记为0,在进行计算的过程中我们相当于没有对于当前待操作节点sum进行更新即可。那么这里对于cnt的计算可以通过普通的拓扑排序进行,在排序过程中只对于0到9的的路径进行记录
- 之后就是从根节点进行一次bfs即可
- 我的代码里把以上的cnt的计算和计算最终结果的bfs合并在一起了,用一个拓扑解决了
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long LL ;
typedef unsigned long long ULL ;
const int maxn = 1e6 + ;
const int inf = 0x3f3f3f3f ;
const int npos = - ;
const LL mod = 1e9 + ;
const int mxx = + ;
const double eps = 1e- ;
const double PI = acos(-1.0) ;
struct topo{
int len, st;
topo(int x, int y){
len=x; st=y;
}
};
bool topocmp(const topo &l, const topo &r){
return l.len<r.len;
}
struct SAM{
struct node{
int len;
int link, go[];
LL cnt, val;
};
node state[maxn<<];
int n, tot, root, last;
void init(char *str){
n=strlen(str);
tot=;
root=;
last=;
memset(&state,,sizeof(state));
state[root].cnt=1LL;
}
void extend(int w){
tot++;
int p=last;
int np=tot;
state[np].len=state[p].len+;
state[np].cnt=0LL;
// state[np].cnt=(w==10?1LL:0LL);
state[np].val=0LL;
while(p && state[p].go[w]==){
state[p].go[w]=np;
p=state[p].link;
}
if(p==){
state[np].link=root;
}else{
int q=state[p].go[w];
if(state[p].len+==state[q].len){
state[np].link=q;
}else{
tot++;
int nq=tot;
state[nq].len=state[p].len+;
state[nq].cnt=state[q].cnt;
state[nq].val=0LL;
memcpy(state[nq].go,state[q].go,sizeof(state[q].go));
state[nq].link=state[q].link;
state[q].link=nq;
state[np].link=nq;
while(p && state[p].go[w]==q){
state[p].go[w]=nq;
p=state[p].link;
}
}
}
last=np;
}
void build(char *str){
init(str);
for(int i=;i<n;i++)
extend(str[i]-'');
}
LL calsum(void){
LL ans=0LL;
std::vector< topo > v;
for(int i=root;i<=tot;i++)
v.push_back(topo(state[i].len,i));
sort(v.begin(),v.end(), topocmp);
int sz=v.size(), p, q;
for(int i=;i<sz;i++){
p=v[i].st;
for(int j=;j<;j++)
if(state[p].go[j]){
q=state[p].go[j];
state[q].cnt+=state[p].cnt;
state[q].val=(state[q].val + ((10LL*state[p].val)%mod + ((LL)j*state[p].cnt)%mod)%mod)%mod;
}
ans=(ans+state[p].val)%mod;
}
ans=(ans+mod)%mod;
return ans;
}
};
SAM A;
int n, lth;
char str[maxn];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(~scanf("%d",&n)){
lth=;
for(int i=;i<=n;i++,lth++){
scanf("%s",str+lth);
lth=strlen(str);
if(i==n){break;}
str[lth]=':';
}
A.build(str);
printf("%lld\n",A.calsum());
}
return ;
}
HDU_1457_后缀自动机四·重复旋律7的更多相关文章
- BZOJ 后缀自动机四·重复旋律7
后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...
- hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品 ...
- 【后缀自动机】【拓扑排序】【动态规划】hihocoder1457 后缀自动机四·重复旋律7
解题方法提示 小Hi:我们已经学习了后缀自动机,今天我们再来看这道有意思的题. 小Ho:好!这道题目让我们求的是若干的数字串所有不同子串的和. 小Hi:你能不能结合后缀自动机的性质来思考如何解决本题? ...
- HIHOcoder 1457 后缀自动机四·重复旋律7
思路 后缀自动机题目,题目本质上是要求求出所有不同的子串的和,SAM每个节点中存放的子串互不相同,所以对于每个节点的sum,可以发现是可以递推的,每个点对子节点贡献是sum[x]*10+c*sz[x] ...
- hihocoder 1457 后缀自动机四·重复旋律7 ( 多串连接处理技巧 )
题目链接 分析 : 这道题对于单个串的用 SAM 然后想想怎么维护就行了 但是多个串下.可以先将所有的串用一个不在字符集( 这道题的字符集是 '0' ~ '9' ) 链接起来.建立后缀自动机之后 在统 ...
- hihoCoder #1457 : 后缀自动机四·重复旋律7(后缀自动机 + 拓扑排序)
http://hihocoder.com/problemset/problem/1457 val[i] 表示状态i所表示的所有字符串的十进制之和 ans= ∑ val[i]在后缀自动机上,从起始状态走 ...
- hihocoder 后缀自动机四·重复旋律6
题目 对于\(k\in[1,n]\)求出长度为\(k\)的子串出现次数最多的出现了多少次 我直到现在才理解后缀自动机上的子树和是什么意思 非常显然的一点是 \[endpos(link(u))⊇endp ...
- hihoCoder.1457.后缀自动机四 重复旋律7(广义后缀自动机)
题目链接 假设我们知道一个节点表示的子串的和sum,表示的串的个数cnt,那么它会给向数字x转移的节点p贡献 \(sum\times 10+c\times cnt\) 的和. 建广义SAM,按拓扑序正 ...
- hihocoder 后缀自动机四·重复旋律7
题目 在\(DAG\)上跑一个\(dp\)就好了 设\(ans_i\)表示到了\(SAM\)的\(i\)位置上所有的子串形成的数的和,之后我们顺便记录一个方案数\(d_i\) 之后我们直接转移就好了 ...
随机推荐
- 如何研究某个gene的ceRNA 网络
研究人员针对 PTEN 这个关键的抑癌基因,来探究调控该基因表达的ceRNA 网络: 分析策略: 1)预测能调控该基因的miRNAs 通过miRanda 软件预测和实验验证相结合的方式,挑选出 miR ...
- vnc远程控制软件怎么用
CC是一款不错的局域网控制软件,它的轻便让人无法相信,下载过该软件的人都知道,该软件只有大小 工具/原料 我这里使用的是vnc-E4_2_9X32中文版 被控制端的安装 1 我们先来被控制电脑 ...
- 消息中间件-ActiveMQ入门实例
1.下载ActiveMQ: http://activemq.apache.org/download-archives.html 2.运行ActiveMQ 解压缩apache-activemq-5.5. ...
- C语言中FILE是结构体,文件类型的指针
c语言文件类型指针 我们在定义文件类型指针变量后,称作该指针指向该文件,但本质上,它不是指向一个存储文件信息的结构型变量么?那么我们在用各个函数对所谓的“文件指针”进行操作时,本质上是不是函数通过获取 ...
- mysql中参数--init-file的作用是什么呢?
需求描述: 今天在修改测试环境mysql数据库中root用户密码的时候,用到了--init-file参数, 所以,就在这里说下该参数的作用. 概念解释: 参数:--init-file=file_nam ...
- mysql的引擎myisam和innodb的区别
1. MYISAM和INNODB的不同?答:主要有以下几点区别: a)构造上的区别 MyISAM在磁盘上存储成三个文件,其中.frm文件存储表定义:.MYD (MYData)为数据文件:. ...
- layui时间,table,大图查看,弹出框,获取音频长度,文件上传
1.引入: <link href="../../Scripts/layui-v2.3.0/css/layui.css" rel="stylesheet" ...
- TCP/IP协议族-----24、网络管理(SNMP)
- mybatis由浅入深day01_ 4.11总结(parameterType_resultType_#{}和${}_selectOne和selectList_mybatis和hibernate本质区别和应用场景)
4.11 总结 4.11.1 parameterType 在映射文件中通过parameterType指定输入参数的类型.mybatis通过ognl从输入对象中获取参数值拼接在sql中. 4.11.2 ...
- python2.0_day20_bbs系统开发
BBS是一个最简单的项目.在我们把本节课程的代码手敲一遍后,算是实战项目有一个入门.首先一个项目的第一步是完成表设计,在没有完成表结构设计之前,千万不要动手开发(这是老司机的忠告!)废话不多说,现在我 ...