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,输出和 ...
随机推荐
-
iOS 对模型对象进行归档
归档是指一种形式的序列化,专门编写用于保存数据的任何对象都应该支持归档.使用对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们. 只要在类中实现的每个属性都是标量或者都是遵循NS ...
-
ARM-linux嵌入式开发平台搭建1
初学嵌入式开发,由于是自学,走了很多弯路,现总结一下嵌入式ARM-LINUX开发环境搭建步骤: 1.安装linux系统,由于初学,我选择fedora 14.安装的具体步骤就不详细说了. 2.安装NFS ...
-
python学习===从一个数中分解出每个数字
题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数",因为153=1 ...
-
Java入门1
一.eclipse的简单使用 1.新建项目 在package explorer的空白处点击右键,新建一个项目(new->Java Project)或者点击菜单栏的File->JavaPro ...
-
Dijkstra算法的C++实现
Dijkstra算法是在图中寻找两顶点最短路径的算法. 下面以下图有向图为例,说明其基本思想. 上图为转化为邻接矩阵存储: 现在我要寻找1点到其他点的最短距离以及路径: a)1点到各点的距 ...
-
机器学习进阶-直方图与傅里叶变化-直方图均衡化 1.cv2.equalizeHist(进行直方图均衡化) 2. cv2.createCLAHA(用于生成自适应均衡化图像)
1. cv2.equalizeHist(img) # 表示进行直方图均衡化 参数说明:img表示输入的图片 2.cv2.createCLAHA(clipLimit=8.0, titleGridSiz ...
-
openstack-on-centos7之各组件服务
认证服务keystone(安装和配置) 在配置 OpenStack 身份认证服务前,必须创建一个数据库和管理员令牌 [用数据库连接客户端以root用户连接到数据库服务] # mysql -u root ...
-
sql嵌套更新
原地址:http://blog.csdn.net/ycb1689/article/details/43834445 方法一: update a set HIGH=b.NEW from SPEC1 a ...
-
怎样增加Dave 英语学习小组
一. 增加小组 英语对IT 是非常重要的,但非常多人都不能坚持去学习,Dave 英语学习小组成立与已经超过半年,如今进行扩招.欢迎想提高英语,而且能够坚持每天学习的人,增加Dave 的小组.并 ...
-
触发器 of oracle
. 本文实例讲述了Oracle触发器用法.分享给大家供大家参考,具体如下: 一.触发器简介 触发器的定义就是说某个条件成立的时候,触发器里面所定义的语句就会被自动的执行. 因此触发器不需要人为的去调用 ...