• 【JZOJ3624】【SDOI2014】数数(count) AC自动机+数位dp


    题面


    100

    容易想到使用AC自动机来处理禁忌子串的问题;
    然后在自动机上数位dp,具体是:
    (f_{i,j,0/1})表示填了(i)位,当前在自动机的第(j)个结点上,(0)表示当前数已经小于了(N)(1)表示当前数等于(N)

    Code

    #include<bits/stdc++.h>
    #define ll long long
    #define fo(i,x,y) for(int i=x;i<=y;i++)
    #define fd(i,x,y) for(int i=x;i>=y;i--)
    using namespace std;
    const char* fin="ex3624.in";
    const char* fout="ex3624.out";
    const int inf=0x7fffffff;
    const int maxn=1507,mo=1000000007;
    struct node{
    	int x,fa,ne[10];
    }ac[maxn];
    int n,m,num=1,hd,tl=1;
    int f[maxn][maxn][2],ne[maxn][10],b[maxn];
    char a[maxn];
    void makefail(){
    	while (hd++<tl){
    		int x=b[hd];
    		fo(i,0,9)
    			if (ac[x].ne[i]){
    				int y=ac[x].ne[i],z=ac[x].fa;
    				if (x){
    					while (z && !ac[z].ne[i]) z=ac[z].fa;
    					ac[y].fa=ac[z].ne[i];
    				}
    				b[++tl]=y;
    				ac[y].x+=ac[ac[y].fa].x;
    			}
    	}
    }
    int main(){
    	freopen(fin,"r",stdin);
    	freopen(fout,"w",stdout);
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	scanf("%d",&m);
    	fo(i,1,m){
    		char ch=getchar();
    		int p=0;
    		while (ch<'0' || ch>'9') ch=getchar();
    		while (ch>='0' && ch<='9'){
    			int x=ch-'0';
    			if (!ac[p].ne[x]) ac[p].ne[x]=++num;
    			p=ac[p].ne[x];
    			ch=getchar();
    		}
    		ac[p].x++;
    	}
    	makefail();
    	fo(i,0,num){
    		if (i==1){
    			ne[1][0]=1;
    			fo(j,1,9) ne[1][j]=ne[0][j];
    			continue;
    		}
    		fo(j,0,9){
    			int x=ac[i].ne[j],y=ac[i].fa;
    			if (x){
    				if (ac[x].x) ne[i][j]=-1;
    				else ne[i][j]=x;
    			}else{
    				while (y && !ac[y].ne[j]) y=ac[y].fa;
    				if (ac[ac[y].ne[j]].x) ne[i][j]=-1;
    				else ne[i][j]=ac[y].ne[j];
    			}
    		}
    	}
    	memset(f,0,sizeof f);
    	f[0][1][0]=1;
    	fo(i,0,n-1)
    		fo(x,0,num){
    			fo(y,0,9){
    				if (ne[x][y]==-1) continue;
    				int z=ne[x][y],xc=a[i+1]-'0';
    				if (y<=xc){
    					if (y<xc) f[i+1][z][1]=(f[i+1][z][1]+f[i][x][0])%mo;
    					else f[i+1][z][0]=(f[i+1][z][0]+f[i][x][0])%mo;
    				}
    				f[i+1][z][1]=(f[i+1][z][1]+f[i][x][1])%mo;
    			}
    		}
    	int ans=0;
    	fo(x,0,num) ans=((ans+f[n][x][0])%mo+f[n][x][1])%mo;
    	ans--;
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    如何给发票抬头增加页签
    记录激活SAP SMTP服务过程
    反射
    乱码问题
    使用idea的常用的技巧
    解决double的值相加的问题
    代理模式之静态代理
    foreach的真面目
    记录java的面试的每一个瞬间
    变量的经典
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6914986.html
Copyright © 2020-2023  润新知