• BZOJ 3530 [Sdoi2014]数数


    题解:建立AC自动机,然后Dp

    考虑长度与n相等时

    f[i][j][2]表示第i位匹配到AC自动机第j号节点,是否顶着上界的方案数

    转移枚举这一位填什么

    注意,如果当前节点沿Fail树能走到单词节点就不能转移到他

    长度<lenn不用考虑顶上界

    问题:不明白最后统计答案的方式

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=2009;
    const int mm=1000000007;
    
    int n,m;
    char s[maxn];
    int a[maxn];
    
    int nn;
    int ch[maxn][10];
    int val[maxn];
    void Ins() {
    	int n=strlen(s);
    	int u=0;
    	for(int i=0; i<n; ++i) {
    		int c=s[i]-'0';
    		if(!ch[u][c])ch[u][c]=++nn;
    		u=ch[u][c];
    	}
    	val[u]=1;
    }
    
    queue<int>q;
    int fai[maxn];
    void Getfail(){
    	for(int c=0;c<=9;++c){
    		int v=ch[0][c];
    		if(v)q.push(v);
    	}
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int c=0;c<=9;++c){
    			int v=ch[u][c];
    			if(!v)continue;
    			q.push(v);
    			val[v]|=val[u];
    			int j=fai[u];
    			while((j)&&(!ch[j][c]))j=fai[j];
    			fai[v]=ch[j][c];
    			val[v]|=val[fai[v]];
    		}
    	}
    }
    
    long long f[maxn][maxn][2];
    long long ans;
    
    int main() {
    	scanf("%s",s);
    	n=strlen(s);
    	for(int i=1; i<=n; ++i)a[i]=s[i-1]-'0';
    	scanf("%d",&m);
    	while(m--) {
    		scanf("%s",s);
    		Ins();
    	}
    	Getfail();
    	
    	memset(f,0,sizeof(f));
    	for(int c=1;c<=9;++c){
    		int v=ch[0][c];
    		if(val[v])continue;
    		if(c<a[1])f[1][v][0]++;
    		if(c==a[1])f[1][v][1]++;
    	}
    	for(int i=1;i<n;++i){
    		for(int j=0;j<=nn;++j){
    			for(int c=0;c<=9;++c){
    				int u=j;
    				while((u)&&(!ch[u][c]))u=fai[u];
    				int v=ch[u][c];
    				if(val[v])continue;
    				if(c<a[i+1]){
    					f[i+1][v][0]=(f[i+1][v][0]+f[i][j][0]+f[i][j][1])%mm;
    				}
    				if(c==a[i+1]){
    					f[i+1][v][0]=(f[i+1][v][0]+f[i][j][0])%mm;
    					f[i+1][v][1]=(f[i+1][v][1]+f[i][j][1])%mm;
    				}
    				if(c>a[i+1]){
    					f[i+1][v][0]=(f[i+1][v][0]+f[i][j][0])%mm;
    				}
    			}
    		}
    	}
    	for(int j=0;j<=nn;++j){
    		ans=(ans+f[n][j][0]+f[n][j][1])%mm;
    	}
    //	ans=(f[n][0][0]+f[n][0][1])%mm;
    //	for(int c=0;c<=9;++c){
    //		int v=ch[0][c];
    //		if(v){
    //			ans=(ans+f[n][v][0]+f[n][v][1])%mm;
    //		}
    //	}
    //	cout<<ans<<endl;
    	--n;
    	memset(f,0,sizeof(f));
    	for(int c=1;c<=9;++c){
    		int v=ch[0][c];
    		if(val[v])continue;
    		f[1][v][0]++;
    	}
    	for(int i=1;i<n;++i){
    		for(int j=0;j<=nn;++j){
    			for(int c=0;c<=9;++c){
    				int u=j;
    				while((u)&&(!ch[u][c]))u=fai[u];
    				int v=ch[u][c];
    				if(val[v])continue;
    				f[i+1][v][0]=(f[i+1][v][0]+f[i][j][0])%mm;
    			}
    		}
    //		ans=(ans+f[i+1][0][0])%mm;
    //		for(int c=0;c<=9;++c){
    //			int v=ch[0][c];
    //			if(!v)continue;
    //			ans=(ans+f[i+1][v][0])%mm;
    //		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=0;j<=nn;++j){
    			ans=(ans+f[i][j][0])%mm;
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

      

    自己还是太辣鸡了
  • 相关阅读:
    MySQL_01 常用命令
    32_Go基础(TCP通信)
    oracle查询优化
    Eclipse中自动添加注释(作者,时间)
    java注解的学习
    JqueryeasyUIdatagrid参数之 queryParams
    Eclipse中,打开文件所在文件夹的插件,及设置
    更改Zend Studio/Eclipse代码风格主题
    JAVA中使用File类批量重命名文件及java.io.File的常见用法
    java面试笔试题大全
  • 原文地址:https://www.cnblogs.com/zzyer/p/8455510.html
Copyright © 2020-2023  润新知