bzoj 3530: [Sdoi2014]数数 数位dp
题目
我们称一个正整数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的更多相关文章
- BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP
BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP Description 正如你所知,奶牛们没有手指以至于不能玩“石头剪刀布”来任意地决定例如谁先挤奶的顺 ...
- BZOJ_1026_[SCOI2009]windy数_数位DP
BZOJ_1026_[SCOI2009]windy数_数位DP 题意:windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之 ...
- BZOJ 3530: [Sdoi2014]数数 [AC自动机 数位DP]
3530: [Sdoi2014]数数 题意:\(\le N\)的不含模式串的数字有多少个,\(n=|N| \le 1200\) 考虑数位DP 对于长度\(\le n\)的,普通套路DP\(g[i][j ...
- BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)
题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...
- [BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】
题目链接:BZOJ - 3530 题目分析 明显是 AC自动机+DP,外加数位统计. WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多.. 其实现在做这道题,我自己也没想出完整解法.. ...
- [BZOJ 1026] [SCOI 2009] Windy数 【数位DP】
题目链接:BZOJ - 1026 题目分析 这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题.. 对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a ...
- [bzoj 1026]windy数(数位DP)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总 ...
- bzoj 1026 [SCOI2009]windy数(数位DP)
1026: [SCOI2009]windy数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4550 Solved: 2039[Submit][Sta ...
- BZOJ 3209 花神的数论题 数位DP+数论
题目大意:令Sum(i)为i在二进制下1的个数 求∏(1<=i<=n)Sum(i) 一道非常easy的数位DP 首先我们打表打出组合数 然后利用数位DP统计出二进制下1的个数为x的数的数量 ...
随机推荐
- idangerous swiper
最近使用Swipe.js,发现中文的资料很少,试着翻译了一下.能力有限,翻译难免错漏,欢迎指出,多谢! 翻译自:http://www.idangero.us/sliders/swiper/api.ph ...
- 【BZOJ4177】Mike的农场 最小割
[BZOJ4177]Mike的农场 Description Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中 ...
- wcf读取message内容
private string MessageToString(ref Message message) { WebContentFormat messageFormat = this.GetMessa ...
- UITableview刷新时界面“乱跑”现象
Self-Sizing在iOS11下是默认开启的,Headers, footers, and cells都默认开启Self-Sizing,所有estimated 高度默认值从iOS11之前的 0 改变 ...
- Struts2-Value Stack浅析
http://my.oschina.net/mlongbo/blog/88250 Value Stack的作用: 1. 可以作为一个数据中转站 2. 用于在前台-后台之间传递数 ...
- QT设置textEdit光标到末尾
//移动光标到末尾 QTextCursor cursor = ui->receiveTextEdit->textCursor(); cursor.movePosition(QTextCur ...
- 找到最大或最小的N个值
对于python原生的数据类型来说,并不存在直接的方法可以找到最大或最小的N个值, 传统的方法必须先排序,然后再截取相应的值,而且对于集合这类数据类型来说还不能直接排序, 需要先转化为列表才行,有的时 ...
- requests ip代理池单ip和多ip设置方式
reqeusts库,在使用ip代理时,单ip代理和多ip代理的写法不同 (目前测试通过,如有错误,请评论指正) 单ip代理模式 省去headers等 import requests proxy = { ...
- mysql主从复制(linux下)
转至:http://369369.blog.51cto.com/319630/790921 怎么安装mysql数据库,这里不说了,只说它的主从复制,步骤如下: 1.主从服务器分别作以下操作: 1. ...
- java-从这里开始认识
<java是什么:>Programming language 程序语言Development environment 开发环境Application environment 应用环境Dep ...