zoukankan      html  css  js  c++  java
  • P3311 [SDOI2014]数数 AC自动机+数位DP

    题意

    给定一个正整数N和n个模式串,问不大于N的数字中有多少个不包含任意模式串,输出对\(1e^9+7\)取模后的答案。

    解题思路

    把所有模式串都加入AC自动机,然后跑数位DP就好了。需要注意的是,这题需要考虑前导0的影响。举个栗子,对于N=2333,在处理数字233时其实处理的是"0233",这时如果不考虑前导0且模式串又包含"0233"的话就会出错。

    消除前导0的影响也很简单,特判一下就可以了,具体请见代码。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn=2e5+5;
    const int mod=1e9+7;
    int len,n;
    char s[2019],t[2019];
    struct AC_Automaton{
    	//root=0,range[1,tot]
    	const static int SIZE=10; 
    	int tr[maxn][SIZE],fail[maxn],tot;
    	
    	int val[maxn];
    	ll dp[2019][2019];
    	
    	inline int newnode(){
    		int p=++tot;
    		memset(tr[p],0,sizeof(tr[p]));
    		val[p]=0;
    		return p;
    	}
    	inline void init(){
    		tot=0;
    		memset(tr[0],0,sizeof(tr[0]));
    		val[0]=0;
    	}
    	inline void insert(char *s){
    		int p=0;
    		for(int i=0;s[i];++i){
    			if(!tr[p][s[i]-'0'])tr[p][s[i]-'0']=newnode();
    			p=tr[p][s[i]-'0'];
    		}
    		val[p]=1;
    	}
    	inline void getfail(){
    		queue<int>q;
    		for(int i=0;i<SIZE;i++)if(tr[0][i])fail[tr[0][i]]=0,q.push(tr[0][i]);
    		while(!q.empty()){
    			int p=q.front();q.pop();
    			for(int i=0;i<SIZE;i++){
    				if(tr[p][i]){
    					fail[tr[p][i]]=tr[fail[p]][i],q.push(tr[p][i]);
    				}
    				else tr[p][i]=tr[fail[p]][i];
    			}
    		}
    	}
    	ll dfs(int p,int pos,int jud,int zero){
    		if(pos==len)return !zero;
    		if(!jud && dp[p][pos]!=-1)return dp[p][pos];
    		int sz=jud?t[pos]-'0':9;
    		ll res=0;
    		for(int i=0;i<=sz;i++){
    			int tmp=tr[p][i];
    			if(val[tmp])continue;
    			res+=dfs(zero?tr[0][i]:tmp,pos+1,jud&&(i==sz),zero&&(i==0));
                 //若是前导0则从根节点开始转移
    			res%=mod;
    		}
    		if(!jud && !zero)dp[p][pos]=res;
    		return res;
    	}
    	inline void solve(char *t){
    		len=strlen(t);
    		memset(dp,-1,sizeof(dp));
    		printf("%lld\n",dfs(0,0,1,1));
    	}
    }A;
    
    int main()
    {
    //#ifndef ONLINE_JUDGE
    //    freopen("in.txt","r",stdin);
    //#endif
    	A.init();
    	scanf("%s",t);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%s",s);
    		A.insert(s);
    	}
    	A.getfail();
    	A.solve(t);
        return 0;
    }
    
  • 相关阅读:
    viewpoint vw适配 兼容方案
    函数参数默认值
    vue v-bind 的prop属性
    vue 全局错误处理 errorHandler
    Python模块学习
    频谱共享---小记
    LTE的信道
    PLMN(公共陆地移动网络)
    单元测试框架GoogleTest
    OpenRAN是什么
  • 原文地址:https://www.cnblogs.com/zengzk/p/11412603.html
Copyright © 2011-2022 走看看