zoukankan      html  css  js  c++  java
  • [SDOI2014]数数

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

    Input
    输入的第一行包含整数N。
    接下来一行一个整数M,表示S中元素的数量。
    接下来M行,每行一个数字串,表示S中的一个元素。

    Output
    输出一行一个整数,表示答案模109+7的值。

    Sample Input
    20
    3
    2
    3
    14

    Sample Output
    14

    HINT
    下表中l表示N的长度,L表示S中所有串长度之和。
    (1leqslant lleqslant1200,1leqslant Mleqslant100,1leqslant Lleqslant1500)


    首先对集合(S)建AC自动机,然后考虑dp,设(f[i][j][0/1])表示目前匹配到第(i)位,在AC自动机上的第(j)位,数是否顶在上界(N)的方案数

    转移则非常简单,具体可以见代码,分是否在上界两种情况讨论即可

    然后建fail指针的时候没有下传标识符导致WA掉……

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1;char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)    putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1.5e3,M=1.2e3,Mod=1e9+7;
    struct S1{
    	int trie[N+10][10],fail[N+10],root,tot;
    	bool End[N+10];
    	void insert(char *s){
    		int len=strlen(s),p=root;
    		for (int i=0;i<len;i++){
    			if (!trie[p][s[i]-'0'])	trie[p][s[i]-'0']=++tot;
    			p=trie[p][s[i]-'0'];
    		}
    		End[p]=1;
    	}
    	void make_fail(){
    		static int h[N+10];
    		int head=1,tail=0;
    		for (int i=0;i<10;i++)	if (trie[root][i])	h[++tail]=trie[root][i];
    		for (;head<=tail;head++){
    			int Now=h[head];
    			End[Now]|=End[fail[Now]];//之前没有下传标识符……
    			for (int i=0;i<10;i++){
    				if (trie[Now][i]){
    					int son=trie[Now][i];
    					fail[son]=trie[fail[Now]][i];
    					h[++tail]=son;
    				}else	trie[Now][i]=trie[fail[Now]][i];
    			}
    		}
    		trie[root][0]=0;
    	}
    }AC;//Aho-Corasick automaton
    int f[M+10][N+10][2];
    char T[M+10];
    int main(){
    	scanf("%s",T+1);
    	int n=read(),len=strlen(T+1);
    	for (int i=1;i<=len;i++)	T[i]-='0';
    	for (int i=1;i<=n;i++){
    		static char s[N+10];
    		scanf("%s",s);
    		AC.insert(s);
    	}
    	AC.make_fail();
    	f[0][0][1]=1;
    	for (int i=0;i<len;i++){
    		for (int j=0;j<=AC.tot;j++){
    			for (int l=0;l<2;l++){
    				if (!f[i][j][l])	continue;
    				for (int k=l?T[i+1]:9;~k;k--){
    					int son=AC.trie[j][k];
    					if (AC.End[son])	continue;
    					f[i+1][son][l&(k==T[i+1])]=(f[i+1][son][l&(k==T[i+1])]+f[i][j][l])%Mod;
    				}
    			}
    		}
    	}
    	ui Ans=Mod-1;
    	for (int i=0;i<=AC.tot;i++)	Ans=(Ans+f[len][i][0]+f[len][i][1])%Mod;
    	printf("%u
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    [Leetcode] generate parentheses 生成括号
    [Leetcode] letter combinations of a phone number 电话号码的字母组合
    MySQL安装出现“不是内部或外部命令,也不是可执行程序”等一系列问题的解决方案
    [Leetcode] sudoku solver 求解数独
    [Leetcode] valid sudoku 有效数独
    jQuery使用(七):事件绑定与取消,及自定事件的实现原理
    前端交互体验核心之事件(一)
    jQuery使用(六):DOM操作之元素包裹、克隆DOM与data的综合应用
    jQuery使用(五):DOM操作之插入和删除元素
    jQuery使用(四):DOM操作之查找兄弟元素和父级元素
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10486151.html
Copyright © 2011-2022 走看看