思路

看到多个子串并且不能包含的情况,想到了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. os.system

    python   os.system os.system()函数在不同的系统下可以实现不同的作用 一.window下: os.system("ping www.baidu.com" ...

  2. How to export a model from SolidWorks to Google SketchUp

    How to export a model from SolidWorks to Google SketchUp While Google SketchUp is not a professional ...

  3. 变量part2

    一 变量值具有三个特征:  1. id:变量值的唯一编号,内存地址不同id则不同  2. type:类型  3. value(值) #name='xia' #print(id(name)) #age= ...

  4. html5-fieldset和legend和keygen元素的用法

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  5. 【转】C#中base关键字的几种用法

    base其实最大的使用地方在面相对性开发的多态性上,base可以完成创建派生类实例时调用其基类构造函数或者调用基类上已被其他方法重写的方法.例如: 2.1关于base调用基类构造函数 public c ...

  6. GitHub 代码上传

    方法一 登录GitHub后,点击下面的图 New responsitory 按钮 或者点击绿色按钮 New repository,新建一个新建一个远程仓库(remote repository),点击后 ...

  7. java 序列化和反序列化的实现原理

    老是听说序列化反序列化,就是不知道到底什么是序列化,什么是反序列化?今天就在网上搜索学习一下,这一搜不要紧,发现自己曾经用过,竟然不知道那就是JDK类库中序列化和反序列化的API. ----什么是序列 ...

  8. 【转载】unittest参数化(paramunittest)

    前言 paramunittest是unittest实现参数化的一个专门的模块,可以传入多组参数,自动生成多个用例 前面讲数据驱动的时候,用ddt可以解决多组数据传入,自动生成多个测试用例.本篇继续介绍 ...

  9. django 函数装饰器 变为 类装饰器

    aaa  

  10. 08: vue组件

    1.1 初识组件 1.什么是组件 1. Html中有组件,是一段可以被复用的结构代码 2. Css中有组件,是一段可以被复用的样式 3. Js中有组件,是一段可以被复用的功能 4. Vue中也有组件, ...