• 【BZOJ3530】[Sdoi2014]数数 AC自动机+数位DP


    【BZOJ3530】[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中所有串长度之和。

    1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500

    题解:本人闲着蛋疼出了套题,考完后同学说这题PPT里有,于是看PPT发现真的有。。。于是跑来水一发~

    先将所有S中的数拿出来建一个AC自动机,然后用f[i][j]表示从AC自动机上的节点i开始走j步有多少种走法。然后数位DP即可。

    注意前导0的情况。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int mod=1000000007;
    int n,m,tot;
    struct node
    {
    	int ch[10],fail,cnt;
    }p[1510];
    int v[1210];
    char str[1210];
    int ans,f[1210][1510];
    queue<int> q;
    void build()
    {
    	int i,j,k,u,v;
    	q.push(1);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=0;i<=9;i++)
    		{
    			if(!p[u].ch[i])
    			{
    				if(u==1)	p[u].ch[i]=1;
    				else	p[u].ch[i]=p[p[u].fail].ch[i];
    				continue;
    			}
    			v=p[u].ch[i],q.push(v);
    			if(u==1)	p[v].fail=1;
    			else	p[v].fail=p[p[u].fail].ch[i],p[v].cnt|=p[p[v].fail].cnt;
    		}
    	}
    	for(i=1;i<=tot;i++)	if(!p[i].cnt)	f[0][i]=1;
    	for(j=1;j<=n;j++)	for(i=1;i<=tot;i++)	for(k=0;k<=9;k++)
    		if(!p[i].cnt)	f[j][i]=(f[j][i]+f[j-1][p[i].ch[k]])%mod;
    }
    int main()
    {
    	int i,j,a,b,u;
    	scanf("%s",str),n=strlen(str);
    	for(i=1;i<=n;i++)	v[i]=str[n-i]-'0';
    	scanf("%d",&m);
    	tot=1;
    	for(i=1;i<=m;i++)
    	{
    		scanf("%s",str),a=strlen(str);
    		for(u=1,j=0;j<a;j++)
    		{
    			b=str[j]-'0';
    			if(!p[u].ch[b])	p[u].ch[b]=++tot;
    			u=p[u].ch[b];
    		}
    		p[u].cnt=1;
    	}
    	build();
    	for(i=1;i<n;i++)	for(j=1;j<=9;j++)	ans=(ans+f[i-1][p[1].ch[j]])%mod;
    	for(u=1,i=n;i>=1;i--)
    	{
    		for(j=(i==n)?1:0;j<v[i];j++)	ans=(ans+f[i-1][p[u].ch[j]])%mod;
    		u=p[u].ch[v[i]];
    		if(p[u].cnt)	break;
    	}
    	if(!p[u].cnt)	ans=(ans+1)%mod;
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    日期时间類(DateTime)的应用
    C# 排版快捷鑑
    撷取指定网址中的资料Part1:WebClinet 的用法
    Chart in Web
    Android APK反编译得到Java源代码和资源文件
    iOS 6.0 GM 版全系列固件下载
    IOS判断设备是否已越狱(isJailbroken)
    批量离线下载迅雷快传资源
    Android如何防止apk程序被反编译
    Java接口学习
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7451880.html
Copyright © 2020-2023  润新知