思路

看到多个子串并且不能包含的情况,想到了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. Unity使用协程技术制作倒计时器

    先上效果图 图片资源来自http://www.51miz.com/ 1.素材准备 在http://www.51miz.com/搜索png格式的数字图片,用Unity自带的图集制作工具,进行分割.Con ...

  2. Java多线程-----线程安全及解决机制

    1.什么是线程安全问题? 从某个线程开始访问到访问结束的整个过程,如果有一个访问对象被其他线程修改,那么对于当前线程而言就发生了线程安全问题: 如果在整个访问过程中,无一对象被其他线程修改,就是线程安 ...

  3. [openjudge-搜索]Knight Moves(翻译与题解)

    题目描述(翻译) somurolov先生,精彩的象棋玩家.声称任何人他都可以从一个位置到另一个骑士这么快.你能打败他吗? 问题 你的任务是写一个程序来计算一个骑士达到从另一点所需要的最少步数,这样你就 ...

  4. sql privot 实现行转列

    表结构如下: RefID    HRMS    Name    InsuranceMoney    InsuranceNamefb2bdee8-e4c9-4470-8e7f-14550d3212f7  ...

  5. 关于git上的一些错误信息

    如果输入$ Git remote add origin git@github.com:djqiang(github帐号名)/gitdemo(项目名).git 提示出错信息:fatal: remote ...

  6. BufferReader BufferWriter

    Copying information from one file to another with 'BufferReader BufferWriter' public class Demo5 { p ...

  7. HTML转义符

    空格的替代符号有以下几种: 名称 编号 描述   &#; 不断行的空白(1个字符宽度)   &#; 半个空白(1个字符宽度)   &#; 一个空白(2个字符宽度)   & ...

  8. Django后端项目---- Rest Framework(2)

    一.认证(补充的一个点) 认证请求头 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import API ...

  9. Censor SCU - 4438

    frog is now a editor to censor so-called sensitive words (敏感词). She has a long text (p). Her job is ...

  10. Sort aborted Error in MySQL Error Log

    现象 [ERROR] lines containing "Sort aborted" are present in the MySQL error log file. [Warni ...