【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)
3530: [Sdoi2014]数数
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 682 Solved: 364Description
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
给定N和S,计算不大于N的幸运数个数。Input
输入的第一行包含整数N。
接下来一行一个整数M,表示S中元素的数量。
接下来M行,每行一个数字串,表示S中的一个元素。Output
输出一行一个整数,表示答案模109+7的值。
Sample Input
20
3
2
3
14Sample Output
14HINT
下表中l表示N的长度,L表示S中所有串长度之和。
1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500
【分析】
这题AC自动机+数位DP。
话说数位DP搞了我好久。主要是联系上AC自动机判病毒串的时候有点卡- -(脑子一片混乱
dp方程:f[i][j]表示现在在点j,继续走i步(不经病毒点)的方案数。
先把长度小于n的加入ans,我是for了一遍长度累加的(前缀0那里有点坑,so...)
然后手动填与n长度相等的串,for一下,判断一下,累加一下,就好了。。 你懂的...
主要部分:

手动填数部分:

注意是不大于N。
完整代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 1600
#define Maxl 1600
#define Mod 1000000007 struct node
{
int fail,mark;
int son[];
}t[Maxn];int tot; int m,sl; void upd(int x)
{
t[x].mark=;
memset(t[x].son,,sizeof(t[x].son));
} char s[Maxl];
char ss[Maxn];
void read_trie()
{
scanf("%s",s+);
int len=strlen(s+);
int now=;
for(int i=;i<=len;i++)
{
int ind=s[i]-''+;
if(!t[now].son[ind])
{
t[now].son[ind]=++tot;
upd(tot);
}
now=t[now].son[ind];
if(i==len) t[now].mark=;
}
} queue<int > q;
void build_AC()
{
while(!q.empty()) q.pop();
q.push();
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=;i<=;i++)
{
if(t[x].son[i])
{
t[t[x].son[i]].fail=x?t[t[x].fail].son[i]:;
q.push(t[x].son[i]);
}
else t[x].son[i]=t[t[x].fail].son[i];
}
if(t[t[x].fail].mark) t[x].mark=;
}
} void init()
{
scanf("%s",ss+);
sl=strlen(ss+);
scanf("%d",&m);
tot=;upd();
for(int i=;i<=m;i++) read_trie();
build_AC();
} int check()
{
for(int i=;i<=sl;i++)
{
bool p=;
int now=;
for(int j=i;j>=;j--)
{
if(t[ t[now].son[ss[j]-''+] ].mark) {p=;break;}
now=t[now].son[ss[j]-''+];
}
if(!p) return i;
}
return ;
} int f[Maxn][Maxn];
void dp()
{
memset(f,,sizeof(f));
for(int i=;i<=tot;i++) f[][i]=;//走到i点,继续填0个数的方案 for(int i=;i<=sl;i++)
{
for(int j=;j<=tot;j++) if(!t[j].mark)
{
for(int k=;k<=;k++) if(!t[t[j].son[k]].mark)
f[i][j]=(f[i][j]+f[i-][t[j].son[k]])%Mod;
}
} int ans=;
if(sl!=)
{
for(int j=;j<=sl;j++)
for(int i=;i<=;i++) if(!t[t[].son[i]].mark)
ans=(ans+f[sl-j][t[].son[i]])%Mod;
} int now=;
bool ok=;
for(int i=sl;i>=;i--)
{
for(int k=;k<ss[sl-i+]-'';k++)//枚举第i位填的数
{
if(i==sl&&k==) continue;
if(t[t[now].son[k+]].mark) continue;
ans=(ans+f[i-][t[now].son[k+]])%Mod;
}
now=t[now].son[ss[sl-i+]-''+];
if(t[now].mark) {ok=;break;}
}
if(ok) ans=(ans+)%Mod;
if(sl==&&ss[]=='') ans=;
printf("%d\n",ans);
} int main()
{
init();
dp();
return ;
}
[HDU3530]
2016-07-14 10:51:01
【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)的更多相关文章
- 【JZOJ3624】【SDOI2014】数数(count) AC自动机+数位dp
题面 100 容易想到使用AC自动机来处理禁忌子串的问题: 然后在自动机上数位dp,具体是: \(f_{i,j,0/1}\)表示填了\(i\)位,当前在自动机的第\(j\)个结点上,\(0\)表示当前 ...
- 【bzoj3530】[Sdoi2014]数数 AC自动机+数位dp
题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...
- BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)
题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...
- BZOJ 3530: [Sdoi2014]数数 [AC自动机 数位DP]
3530: [Sdoi2014]数数 题意:\(\le N\)的不含模式串的数字有多少个,\(n=|N| \le 1200\) 考虑数位DP 对于长度\(\le n\)的,普通套路DP\(g[i][j ...
- BZOJ3530:[SDOI2014]数数(AC自动机,数位DP)
Description 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3 ...
- BZOJ3530[Sdoi2014]数数——AC自动机+数位DP
题目描述 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3223不是幸运 ...
- [SDOI2014]数数 --- AC自动机 + 数位DP
[SDOI2014]数数 题目描述: 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串. 例如当S=(22,333,0233)时,233是幸运数,2333 ...
- P3311 [SDOI2014]数数 AC自动机+数位DP
题意 给定一个正整数N和n个模式串,问不大于N的数字中有多少个不包含任意模式串,输出对\(1e^9+7\)取模后的答案. 解题思路 把所有模式串都加入AC自动机,然后跑数位DP就好了.需要注意的是,这 ...
- HDU-4518 吉哥系列故事——最终数 AC自动机+数位DP
题意:如果一个数中的某一段是长度大于2的菲波那契数,那么这个数就被定义为F数,前几个F数是13,21,34,55......将这些数字进行编号,a1 = 13, a2 = 21.现给定一个数n,输出和 ...
随机推荐
- 基于 CoreText 实现的高性能 UITableView
引起UITableView卡顿比较常见的原因有cell的层级过多.cell中有触发离屏渲染的代码(譬如:cornerRadius.maskToBounds 同时使用).像素是否对齐.是否使用UITab ...
- SpringMVC项目学习1_web.xml
最近接触的所有项目都是SpringMVC+ajax的项目,因此以一个项目为例学习下. --------------------------------------------------------- ...
- Java 反射学习笔记
要学反射,先要了解Class这个类,Class是所有Java类的一个总称,Class的实例中存储的是一个类的字节码,获取Class的实例有三种方式: System.class new Date().g ...
- windows向ubuntu过渡之常用编程软件安装
不出意外的上篇文章又被踢出首页了,心情甚是悲桑..希望更多人能看到 1.安装codeblocks 直接在软件中心搜索codeblocks就可以 2.安装jdk并配置环境变量 http://www.li ...
- Bootstrap 样式定制-lessc编译源码
1.github上下载源码:解压:如目录bootstrap 2.新建同级目录custom-bootstrap ,在该目录下新建 如下三个文件:其实就是bootstrap下面的bootstrap.les ...
- 使用linq获得当前文件夹下的下一级满足条件的文件夹
使用linq获得当前文件夹下的下一级满足条件的文件夹. SPFolderCollection subAlbums = Folder.SubFolders; ...
- [GDI+] C# ImageDown帮助类教程与源码下载 (转载)
点击下载 ImageDown.zip 1.下载图片到本地代码如下 /// <summary> /// 编 码 人:苏飞 /// 联系方式:361983679 /// 更新网站:[url=h ...
- c语言学习之基础知识点介绍(一):输出语句和变量简单介绍
本系列是为了学习ios做准备的,也能作为c语言入门的教程看看. c语言的程序结构: 1.顺序结构:自上而下依次执行. 2.分支结构:程序有选择的执行某段代码或者不执行某段代码. 3.循环结构:程序循环 ...
- MyEclipse中配置自己的JRE和tomcat
MyEclipse中配置自己的JRE:windows>Preference>java>Installed JREs>Add>Stantard VM>next> ...
- CSS 导航栏
实例: 导航栏 Home News Articles Forum Contact About 导航栏 熟练使用导航栏,对于任何网站都非常重要. 使用CSS你可以转换成好看的导航栏而不是枯燥的HTML菜 ...