题目

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

给定N和S,计算不大于N的幸运数个数。

题解

有一道scoi2013的数数比这道题丧病多了...

这道题还是比较好做的。

给定范围的时给定了n的长度,并且要求计算数的个数。

所以可以基本确定这是一道数位dp了。

然后又要求有一部分串不能出现

这是经典的在AC自动机上的dp了.

所以我们需要在拿到的数不超过n的情况下在AC自动机上dp.

可以这么设定状态:

\(f[i][j]\)表示从高位向低位逐个确定了\(n\)位,走到了自动机的节点\(j\)

但是要求我们找出来的串的大小不得超过\(n\),所以我们现在的状态无法支持转移.

原因就在于我们没有办法确定下一位取值的范围,可能是\([0,a_i]\),也可能是\([0,9]\)

所以需要多加一维的状态表示我们前面的数字是不是顶到顶了.

所谓顶到顶的意思就是下一位只能取\([0,a_i]\)范围内的数.

所以我们两维状态交替更新即可.细节看代码.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;static char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 2048;
const int mod = 1e9+7;
int ch[maxn][10],nodecnt,fail[maxn],q[maxn],l,r;
bool danger[maxn];
inline void insert(char *s){
int nw = 0;
for(rg i=0,c;s[i];++i){
c = s[i] - '0';
if(ch[nw][c] == 0) ch[nw][c] = ++ nodecnt;
nw = ch[nw][c];
}danger[nw] = true;
}
void build(){
l = 0;r = -1;
rep(c,0,9){
if(ch[0][c] != 0){
fail[ch[0][c]] = 0;
q[++r] = ch[0][c];
}
}
while(l <= r){
int u = q[l++];
rep(c,0,9){
int t = ch[fail[u]][c];
if(ch[u][c] == 0) ch[u][c] = t;
else{
danger[ch[u][c]] |= danger[t];
fail[ch[u][c]] = t;
q[++r] = ch[u][c];
}
}
}
}
char num[maxn],s[maxn];
int f[maxn][maxn][2],a[maxn];
int main(){
scanf("%s",num+1);
int n = strlen(num+1);
rep(i,1,n) a[i] = num[i] - '0';
int m;read(m);
while(m--){
scanf("%s",s);
insert(s);
}build();
rep(i,1,a[1]) if(!danger[ch[0][i]]){
f[1][ch[0][i]][i == a[1]] += 1;
}
rep(i,1,n-1) rep(j,0,nodecnt){
if(f[i][j][1]){
rep(k,0,a[i+1]){
if(danger[ch[j][k]]) continue;
f[i+1][ch[j][k]][k == a[i+1]] += f[i][j][1];
if(f[i+1][ch[j][k]][k == a[i+1]]>=mod)f[i+1][ch[j][k]][k == a[i]] -= mod;
}
}
if(f[i][j][0]){
rep(k,0,9){
if(danger[ch[j][k]]) continue;
f[i+1][ch[j][k]][0] += f[i][j][0];
if(f[i+1][ch[j][k]][0] >= mod) f[i+1][ch[j][k]][0] -= mod;
}
}
}
ll ans = 0;
rep(i,0,nodecnt){
ans += f[n][i][0] + f[n][i][1];
if(ans >= mod) ans -= mod;
}
memset(f,0,sizeof f);
rep(i,1,9) if(!danger[ch[0][i]]) f[1][ch[0][i]][0] += 1;
rep(i,1,n-2) rep(j,0,nodecnt){
if(f[i][j][0]){
rep(k,0,9){
if(danger[ch[j][k]]) continue;
f[i+1][ch[j][k]][0] += f[i][j][0];
if(f[i+1][ch[j][k]][0] >= mod) f[i+1][ch[j][k]][0] -= mod;
}
}
}
rep(i,1,n-1){
rep(j,0,nodecnt){
ans += f[i][j][0];
if(ans >= mod) ans -= mod;
}
}
printf("%lld\n",ans);
return 0;
}

bzoj 3530: [Sdoi2014]数数 数位dp的更多相关文章

  1. BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP

    BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP Description 正如你所知,奶牛们没有手指以至于不能玩“石头剪刀布”来任意地决定例如谁先挤奶的顺 ...

  2. BZOJ_1026_[SCOI2009]windy数_数位DP

    BZOJ_1026_[SCOI2009]windy数_数位DP 题意:windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之 ...

  3. BZOJ 3530: [Sdoi2014]数数 [AC自动机 数位DP]

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

  4. BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)

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

  5. [BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】

    题目链接:BZOJ - 3530 题目分析 明显是 AC自动机+DP,外加数位统计. WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多.. 其实现在做这道题,我自己也没想出完整解法.. ...

  6. [BZOJ 1026] [SCOI 2009] Windy数 【数位DP】

    题目链接:BZOJ - 1026 题目分析 这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题.. 对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a ...

  7. [bzoj 1026]windy数(数位DP)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总 ...

  8. bzoj 1026 [SCOI2009]windy数(数位DP)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4550  Solved: 2039[Submit][Sta ...

  9. BZOJ 3209 花神的数论题 数位DP+数论

    题目大意:令Sum(i)为i在二进制下1的个数 求∏(1<=i<=n)Sum(i) 一道非常easy的数位DP 首先我们打表打出组合数 然后利用数位DP统计出二进制下1的个数为x的数的数量 ...

随机推荐

  1. 仿照ArrayList自己生成的MyList对象

    现在需要自己生成一个list集合,基本雷同ArrayList,不使用API的List接口. 实现如下: MyList的代码: public class MyList<T> { privat ...

  2. saltStack 证书管理

    SaltStack 使用 SSL 签证的方式进行安全认证,我们可以在 Master 端看到 Minion 端的整数签证请求 1.查看当前证书签证情况 [root@SaltStack-Master ~] ...

  3. Python中pymysql模块详解

    安装 pip install pymysql 使用操作 执行SQL #!/usr/bin/env pytho # -*- coding:utf-8 -*- import pymysql # 创建连接 ...

  4. Linux软连接和硬连接

    软连接 命令: ln -s 原文件 目标文件 特征: 1.相当于windows的快捷方式 2.只是一个符号连接,所以软连接文件大小都很小 3.当运行软连接的时候,会根据连接指向找到真正的文件,然后执行 ...

  5. ubuntun下安装Fiddler

    对于分析网页或者写爬虫的时候经常需要用到抓包工具进行网页数据的抓包.在Windows下可以安装Fiddler来抓包.在ubuntun下不能直接安装Fiddler.需要先安装mono 1 首先安装mon ...

  6. 培训笔记——ubuntu安装

    1.选择安装位置,如果是做双系统提前准备一个分区,如果覆盖安装就无所谓了2.下载iso镜像文件,制作启动盘,Windows或linux环境下分别有相应的软件可以制作启动光盘或U盘3.开始安装一 设置开 ...

  7. 每天一个Linux命令(18)loacte命令

    locate 让使用者可以很快速的搜寻档案系统内是否有指定的档案.     (1)用法:   用法:  Locate  [选项] [参数]     (2)功能: 功能:  在mlocate数据库中搜索 ...

  8. 新手用的git配置命令

    新手用的git配置命令 /**第一次链接远程仓库 本地已有项目需要上传码云 */ //1.配置码云用户名 git config --global user.name "昵称" // ...

  9. 用Delphi模拟键盘输入

    在Windows大行其道的今天,windows界面程序受到广大用户的欢迎.对这些程序的操作不外乎两种,键盘输入控制和鼠标输入控制.有时,对于繁杂的,或重复性的操作,我们能否通过编制程序来代替手工输入, ...

  10. fzu 1476 矩形个数

    注意点:精度 #include<iostream> using namespace std; typedef long long ll; int main() { int a,b; ll ...