您的位置:首页 > 其它

[bzoj3530][SDOI2014]数数

2015-12-30 19:53 477 查看

题目描述

求不大于N的所有正整数中有多少个满足以下条件的数:给定字符串集合S,把该数当作字符串(没有前导0),集合S中没有任意一个字符串是该字符串的子集。

N的长度不超过1200,集合中所有字符串长度和不超过1500。

AC自动机上的DP

将集合内所有字符串建出一颗AC自动机。

那么,我们需要预处理一个这样的next[i,j]表示在结点i上接下要走j的话会调整到的结点是什么。(即预处理所有可能出现的调整结果)。

接下来就是数位DP了,设f[i,j,0]表示在第i位在AC自动机的结点j,当前比前i位比N小,那么f[i,j,1]就是与N相同,转移显然。

跳过所有状态满足当前结点可以匹配到一个单词(即S内的一个字符串),这样的结点j满足bz[j]=1(它是单词结点)或last[j]>0(它可以通过fail指针调整而匹配成功)。

参考程序

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<deque>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll mo=1000000007;
struct dong{
ll x,y;
};
deque<dong> dl;
ll next[1500+10][15],g[1500+10][15],fail[1500+10],last[1500+10];
bool bz[1500+10];
ll f[1200+10][1500+10][2];
ll i,j,k,l,t,n,m,top,tot,ans;
char s[1500+10],h[1500+10],ch;
dong zlt;
void insert(ll x,ll y){
if (y>top){
bz[x]=1;
return;
}
if (g[x][h[y]-'0']==-1){
g[x][h[y]-'0']=++tot;
ll i;
fo(i,0,9) g[tot][i]=-1;
}
insert(g[x][h[y]-'0'],y+1);
}
void bfs(){
fo(i,0,9)
if (g[0][i]!=-1){
zlt.x=g[0][i];zlt.y=0;
dl.push_back(zlt);
}
while (!dl.empty()){
zlt=dl.front();
dl.pop_front();
k=zlt.x;l=zlt.y;
fail[k]=l;
if (bz[l]) last[k]=l;else last[k]=last[l];
fo(i,0,9){
if (g[k][i]==-1) continue;
j=l;
while (j&&g[j][i]==-1) j=fail[j];
if (g[j][i]!=-1) j=g[j][i];
zlt.x=g[k][i];zlt.y=j;
dl.push_back(zlt);
}
}
}
void getnext(){
fo(i,0,tot){
fo(k,0,9){
j=i;
while (j&&g[j][k]==-1) j=fail[j];
if (g[j][k]!=-1) j=g[j][k];
next[i][k]=j;
}
}
}
int main(){
//freopen("count.in","r",stdin);freopen("count.out","w",stdout);
do{
ch=getchar();
if (ch=='\n') break;
s[++n]=ch;
}while (1);
scanf("%lld",&m);
ch=getchar();
fo(i,0,9) g[0][i]=-1;
fo(i,1,m){
top=0;
do{
ch=getchar();
if (ch=='\n') break;
h[++top]=ch;
}while (1);
insert(0,1);
}
bfs();
getnext();
fo(i,1,s[1]-'0'-1) f[1][next[0][i]][0]=(f[1][next[0][i]][0]+1)%mo;
f[1][next[0][s[1]-'0']][1]=(f[1][next[0][s[1]-'0']][1]+1)%mo;
fo(i,1,n-1){
fo(j,1,9) f[i+1][next[0][j]][0]=(f[i+1][next[0][j]][0]+1)%mo;
fo(j,0,tot){
if (bz[j]||last[j]) continue;
if (f[i][j][0])
fo(k,0,9) f[i+1][next[j][k]][0]=(f[i+1][next[j][k]][0]+f[i][j][0])%mo;
if (f[i][j][1]){
fo(k,0,s[i+1]-'0'-1) f[i+1][next[j][k]][0]=(f[i+1][next[j][k]][0]+f[i][j][1])%mo;
f[i+1][next[j][s[i+1]-'0']][1]=(f[i+1][next[j][s[i+1]-'0']][1]+f[i][j][1])%mo;
}
}
}
ans=0;
fo(i,0,tot)
if (!bz[i]&&!last[i]) ans=(ans+f
[i][0]+f
[i][1])%mo;
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: