思路

看到多个子串并且不能包含的情况,想到了AC自动机

但是题目多了一个不能大于给出的n的限制条件,联想数位dp的过程,设f[i][j][0/1]表示在第i位,AC自动机的第j个节点,数位有/无限制的方案数

dp方程就是对应的转移到子节点即可,不向有标记的节点转移

注意如果跳fail能够跳到限制节点,就也不能转移,因为fail树上的父节点是子节点的子串,如果父节点是单词节点,子节点一定包含单词

另外题目中的数不能出现前导零,所以从根节点向子节点转移时不能转移到根的0号子节点

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define int long long
const int MOD = 1000000007;
using namespace std;
int trie[1501][10],Nodecnt,fail[1501],mark[1501],root,f[1201][1501][2],lens,lent;
char s[1501],t[1501];
void insert(char *s,int len){
int o=root;
for(int i=1;i<=len;i++){
if(!trie[o][s[i]-'0'])
trie[o][s[i]-'0']=++Nodecnt;
o=trie[o][s[i]-'0'];
}
mark[o]++;
}
void get_fail(void){
queue<int> q;
for(int i=0;i<10;i++){
if(trie[root][i]){
fail[trie[root][i]]=root;
q.push(trie[root][i]);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<10;i++){
if(trie[x][i]){
fail[trie[x][i]]=trie[fail[x]][i];
// mark[trie[x][i]]|=mark[trie[fail[x]][i]];
q.push(trie[x][i]);
}
else{
trie[x][i]=trie[fail[x]][i];
}
}
}
}
void getban(void){
for(int i=0;i<=Nodecnt;i++){
int p=i;
for(;p;p=fail[p])
if(mark[p]){
mark[i]=true;
break;
}
}
}
int dp(void){
for(int i=0;i<lens;i++){
for(int j=0;j<=Nodecnt;j++){
if(f[i][j][0]){
for(int k=0;k<s[i+1]-'0';k++)
if(!mark[trie[j][k]])
f[i+1][trie[j][k]][1]=(f[i+1][trie[j][k]][1]+f[i][j][0])%MOD;
if(!mark[trie[j][s[i+1]-'0']])
f[i+1][trie[j][s[i+1]-'0']][0]=(f[i+1][trie[j][s[i+1]-'0']][0]+f[i][j][0])%MOD;
}
if(f[i][j][1]){
for(int k=0;k<10;k++)
if(!mark[trie[j][k]])
f[i+1][trie[j][k]][1]=(f[i+1][trie[j][k]][1]+f[i][j][1])%MOD;
}
if(!j){
if(!i){
for(int k=1;k<s[i+1]-'0';k++)
if(!mark[trie[j][k]])
f[i+1][trie[j][k]][1]=(1+f[i+1][trie[j][k]][1])%MOD;
if(!mark[trie[j][s[i+1]-'0']])
f[i+1][trie[j][s[i+1]-'0']][0]=(1+f[i+1][trie[j][s[i+1]-'0']][0])%MOD;
}
else{
for(int k=1;k<10;k++)
if(!mark[trie[j][k]])
f[i+1][trie[j][k]][1]=(1+f[i+1][trie[j][k]][1])%MOD;
}
}
}
}
int ans=0;
for(int i=0;i<=Nodecnt;i++)
ans=(f[lens][i][0]+f[lens][i][1]+ans)%MOD;
return ans;
}
signed main(){
scanf("%s",s+1);
lens=strlen(s+1);
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%s",t+1);
lent=strlen(t+1);
insert(t,lent);
}
get_fail();
getban();
// for(int i=1;i<=Nodecnt;i++)
// if(mark[i])
// printf("%d!\n",i);
printf("%lld\n",dp());
return 0;
}

P3311 [SDOI2014]数数的更多相关文章

  1. 【BZOJ】【3530】【SDOI2014】数数

    AC自动机/数位DP orz zyf 好题啊= =同时加深了我对AC自动机(这个应该可以叫Trie图了吧……出边补全!)和数位DP的理解……不过不能自己写出来还真是弱…… /************* ...

  2. BZOJ3530: [Sdoi2014]数数

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 322  Solved: 188[Submit][Status] ...

  3. 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 682  Solved: 364 Description 我们称一 ...

  4. BZOJ 3530: [Sdoi2014]数数 [AC自动机 数位DP]

    3530: [Sdoi2014]数数 题意:\(\le N\)的不含模式串的数字有多少个,\(n=|N| \le 1200\) 考虑数位DP 对于长度\(\le n\)的,普通套路DP\(g[i][j ...

  5. 「SDOI2014」数数 解题报告

    「SDOI2014」数数 题目描述 我们称一个正整数 \(N\) 是幸运数,当且仅当它的十进制表示中不包含数字串集合 \(S\) 中任意一个元素作为其子串. 例如当 \(S=(\)22, 333, 0 ...

  6. 3530: [Sdoi2014]数数

    3530: [Sdoi2014]数数 链接 分析: 对给定的串建立AC自动机,然后数位dp.数位dp的过程中,记录当前在AC自动机的哪个点上,保证不能走到出现了给定串的点. 代码: #include& ...

  7. [SDOI2014]数数 --- AC自动机 + 数位DP

    [SDOI2014]数数 题目描述: 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串. 例如当S=(22,333,0233)时,233是幸运数,2333 ...

  8. bzoj [Sdoi2014]数数 AC自动机上dp

    [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1264  Solved: 636[Submit][Status][Discu ...

  9. [Sdoi2014]数数[数位dp+AC自动机]

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 834  Solved: 434[Submit][Status][ ...

  10. [bzoj3530][Sdoi2014]数数_AC自动机_数位dp

    数数 bzoj-3530 Sdoi-2014 题目大意:给你一个整数集合,求所有不超过n的正整数,是的它的十进制表示下不能再一段等于集合中的任意数. 注释:$1\le n \le 1200$,$1\l ...

随机推荐

  1. 步进电机 28BYJ-48介绍和驱动及编程

    28BYJ-48步进电机: 步进电机是一种将电脉冲转化为角位移的执行机构.通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角).您可以通过控制脉冲个来 ...

  2. CSS小知识-----前缀-moz-、-ms-、-webkit-,-o-分别代表的意思

    这种方式在业界上统称:识别码.前缀 -ms-代表[ie]内核识别码 -moz-代表火狐[firefox]内核识别码 -webkit-代表谷歌[chrome]/苹果[safari]内核识别码 -o-代表 ...

  3. 检测FTP服务并开启FTP服务

    1. 检测FTP服务是否开启 1.1. 通过查询提供FTP服务的进程是否存在,并未找到任何包含ftp关键字的进程信息,可判断服务未开启. root@lb- ~ # ps -ef | grep ftp ...

  4. Python: 字典dict: 相同点

    问题:怎么样在两个字典中找相同点 answer: eg1: 下面2个字典 a={'x':1,'y':2,'z':3},    b={'w':10,'x':11,'y':2}, 1)找相同点: a.ke ...

  5. curl 命令简介

    curl命令用于在命令行中发送HTTP请求: curl -i -H 'content-type: application/json' -X POST -d '{"name":&qu ...

  6. linux常用命令:more 命令

    more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会 ...

  7. RocketMQ 顺序消费只消费一次 坑

    rocketMq实现顺序消费的原理 produce在发送消息的时候,把消息发到同一个队列(queue)中,消费者注册消息监听器为MessageListenerOrderly,这样就可以保证消费端只有一 ...

  8. storm的trident编程模型

    storm的基本概念别人总结的, https://blog.csdn.net/pickinfo/article/details/50488226 编程模型最关键最难就是实现局部聚合的业务逻辑聚合类实现 ...

  9. hive 用户行为分析(活跃。启动,留存,回访,新增)的一些经典sql

    很简单的sql 用户分析语句 :只要自定义简单的udf函数 获取统计时间createdatms字段的使用的日历类 add方法 和simpledateformat 将long类型的 定义多个重载方法 获 ...

  10. mac shell终端编辑命令行快捷键——行首,行尾

    Ctrl + d        删除一个字符,相当于通常的Delete键(命令行若无所有字符,则相当于exit:处理多行标准输入时也表示eof) Ctrl + h        退格删除一个字符,相当 ...