P3311 [SDOI2014]数数

P3311 [SDOI2014]数数

看到匹配,自然想到AC自动机

控制位数的当然容易做,\(emmm\) 这里是要求小于\(n\),后面不会了怎么办

好像和数位dp有点关系,首先\(dp1_{i,j}\)跑一边,小于\(strlen(n)\)长度的个数

重点来了,\(dp2_{i,j,1/0}\) 第三维表示是否达到上界

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn=2000000;
const LL MOD=1e9+7;
LL n,ans,nod,m;
LL son[maxn][20],val[maxn],dp1[6000][6000],dp2[6000][6000][2],fail[maxn];
char book[maxn],s[maxn];
inline void Build(char *s){
	LL len=strlen(s),u=0;
	for(LL i=0;i<len;++i){
		LL c=s[i]-'0';
		if(!son[u][c])
		    son[u][c]=++nod;
		u=son[u][c];
	}
	val[u]|=1;
}
inline void Bfail(){
	queue<LL> que;
	for(LL i=0;i<10;++i)
	    if(son[0][i])
	        que.push(son[0][i]);
    while(que.size()){
    	LL u=que.front(); que.pop();
    	for(LL i=0;i<10;++i){
    		LL v=son[u][i];
    		if(v)
    		    fail[v]=son[fail[u]][i],
    		    val[v]|=val[fail[v]],
    		    que.push(v);
    		else 
    		    son[u][i]=son[fail[u]][i];
		}
	}
}
inline void Solve(){
	dp1[0][0]=1;
	for(LL i=0;i<n;++i){
	    for(LL u=0;u<=nod;++u){
	    	if(val[u])
	    	    continue;
	    	for(LL k=0;k<10;++k){
	    		LL v=son[u][k];
	    		if(val[v])
	    		    continue;
	    		if(!i&&!k)
	    		    continue;
	    		dp1[i+1][v]=(dp1[i+1][v]+dp1[i][u])%MOD;
			}
		}
	}
	for(LL i=1;i<n;++i)
	    for(LL u=0;u<=nod;++u)
	        ans=(ans+dp1[i][u])%MOD;
	dp2[0][0][1]=1;
	for(LL i=0;i<n;++i){
		for(LL u=0;u<=nod;++u){
			if(val[u])
			    continue;
			for(LL k=0;k<10;++k){
				LL v=son[u][k];
				if(val[v])
				    continue;
				if(!i&&!k)
				    continue;
				dp2[i+1][v][0]=(dp2[i+1][v][0]+dp2[i][u][0])%MOD;
				if(book[i]-'0'>k)
				    dp2[i+1][v][0]=(dp2[i+1][v][0]+dp2[i][u][1])%MOD;
				if(book[i]-'0'==k)
				    dp2[i+1][v][1]=(dp2[i+1][v][1]+dp2[i][u][1])%MOD;
			}
		}
	}
	for(LL u=0;u<=nod;++u)
	    ans=(ans+dp2[n][u][0])%MOD,
	    ans=(ans+dp2[n][u][1])%MOD;
}
int main(){
	scanf(" %s",book);
	n=strlen(book);
	scanf("%lld",&m);
	for(LL i=1;i<=m;++i)
	    scanf(" %s",s),
	    Build(s);
	Bfail();
	Solve();
	printf("%lld",ans);
	return 0;
}
posted @ 2018-12-21 18:09  y2823774827y  阅读(138)  评论(0编辑  收藏  举报