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

时间:2021-12-30 13:20:38

3530: [Sdoi2014]数数

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 682  Solved: 364

Description

我们称一个正整数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
14

Sample Output

14

HINT

下表中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一下,判断一下,累加一下,就好了。。 你懂的...

  

  主要部分:

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

手动填数部分:

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

  注意是不大于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)的更多相关文章

  1. 【JZOJ3624】【SDOI2014】数数&lpar;count&rpar; AC自动机&plus;数位dp

    题面 100 容易想到使用AC自动机来处理禁忌子串的问题: 然后在自动机上数位dp,具体是: \(f_{i,j,0/1}\)表示填了\(i\)位,当前在自动机的第\(j\)个结点上,\(0\)表示当前 ...

  2. 【bzoj3530】&lbrack;Sdoi2014&rsqb;数数 AC自动机&plus;数位dp

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

  3. BZOJ 3530 &lbrack;SDOI2014&rsqb;数数 &lpar;Trie图&sol;AC自动机&plus;数位DP&rpar;

    题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...

  4. BZOJ 3530&colon; &lbrack;Sdoi2014&rsqb;数数 &lbrack;AC自动机 数位DP&rsqb;

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

  5. BZOJ3530&colon;&lbrack;SDOI2014&rsqb;数数&lpar;AC自动机&comma;数位DP&rpar;

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

  6. BZOJ3530&lbrack;Sdoi2014&rsqb;数数——AC自动机&plus;数位DP

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

  7. &lbrack;SDOI2014&rsqb;数数 --- AC自动机 &plus; 数位DP

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

  8. P3311 &lbrack;SDOI2014&rsqb;数数 AC自动机&plus;数位DP

    题意 给定一个正整数N和n个模式串,问不大于N的数字中有多少个不包含任意模式串,输出对\(1e^9+7\)取模后的答案. 解题思路 把所有模式串都加入AC自动机,然后跑数位DP就好了.需要注意的是,这 ...

  9. HDU-4518 吉哥系列故事——最终数 AC自动机&plus;数位DP

    题意:如果一个数中的某一段是长度大于2的菲波那契数,那么这个数就被定义为F数,前几个F数是13,21,34,55......将这些数字进行编号,a1 = 13, a2 = 21.现给定一个数n,输出和 ...

随机推荐

  1. iOS 对模型对象进行归档

    归档是指一种形式的序列化,专门编写用于保存数据的任何对象都应该支持归档.使用对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们. 只要在类中实现的每个属性都是标量或者都是遵循NS ...

  2. ARM-linux嵌入式开发平台搭建1

    初学嵌入式开发,由于是自学,走了很多弯路,现总结一下嵌入式ARM-LINUX开发环境搭建步骤: 1.安装linux系统,由于初学,我选择fedora 14.安装的具体步骤就不详细说了. 2.安装NFS ...

  3. python学习&equals;&equals;&equals;从一个数中分解出每个数字

    题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数",因为153=1 ...

  4. Java入门1

    一.eclipse的简单使用 1.新建项目 在package explorer的空白处点击右键,新建一个项目(new->Java Project)或者点击菜单栏的File->JavaPro ...

  5. Dijkstra算法的C&plus;&plus;实现

    Dijkstra算法是在图中寻找两顶点最短路径的算法.   下面以下图有向图为例,说明其基本思想. 上图为转化为邻接矩阵存储:     现在我要寻找1点到其他点的最短距离以及路径: a)1点到各点的距 ...

  6. 机器学习进阶-直方图与傅里叶变化-直方图均衡化 1&period;cv2&period;equalizeHist&lpar;进行直方图均衡化&rpar; 2&period; cv2&period;createCLAHA&lpar;用于生成自适应均衡化图像&rpar;

    1. cv2.equalizeHist(img)  # 表示进行直方图均衡化 参数说明:img表示输入的图片 2.cv2.createCLAHA(clipLimit=8.0, titleGridSiz ...

  7. openstack-on-centos7之各组件服务

    认证服务keystone(安装和配置) 在配置 OpenStack 身份认证服务前,必须创建一个数据库和管理员令牌 [用数据库连接客户端以root用户连接到数据库服务] # mysql -u root ...

  8. sql嵌套更新

    原地址:http://blog.csdn.net/ycb1689/article/details/43834445 方法一: update a set HIGH=b.NEW  from SPEC1 a ...

  9. 怎样增加Dave 英语学习小组

    一.     增加小组 英语对IT 是非常重要的,但非常多人都不能坚持去学习,Dave 英语学习小组成立与已经超过半年,如今进行扩招.欢迎想提高英语,而且能够坚持每天学习的人,增加Dave 的小组.并 ...

  10. 触发器 of oracle

    . 本文实例讲述了Oracle触发器用法.分享给大家供大家参考,具体如下: 一.触发器简介 触发器的定义就是说某个条件成立的时候,触发器里面所定义的语句就会被自动的执行. 因此触发器不需要人为的去调用 ...