zoukankan      html  css  js  c++  java
  • [bzoj3530][Sdoi2014]数数_AC自动机_数位dp

    数数 bzoj-3530 Sdoi-2014

    题目大意:给你一个整数集合,求所有不超过n的正整数,是的它的十进制表示下不能再一段等于集合中的任意数。

    注释:$1le n le 1200$,$1le |S|le 100$,$1le Lle 1500$,L是总长度之和。

    想法:咳咳,显然,我们... ...什么都不想,看着能开下先把AC自动机扔出来

    然后,其实数位dp就可以了

    具体看代码

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define mod 1000000007 
    using namespace std;
    typedef long long ll;
    struct tree
    {
    	int fail;
    	int vis[11];
    	int end;
    }a[1600];
    char s[1600],t[1250];
    int n,m,cnt;
    ll f[3][1250][1600],ans;
    void build(char *s)
    {
    	int l=strlen(s);
    	int now=0;
    	for(int i=0;i<l;i++)
    	{
    		int x=s[i]-'0';
    		if(!a[now].vis[x])
    		{
    			a[now].vis[x]=++cnt;
    		}
    		now=a[now].vis[x];
    	}
    	a[now].end|=1;
    }
    queue<int>q;
    void getfail()
    {
    	while(!q.empty()) q.pop();
    	for(int i=0;i<10;i++)
    	{
    		if(a[0].vis[i]!=0)
    		{
    			a[a[0].vis[i]].fail=0;
    			q.push(a[0].vis[i]);
    		}
    	}
    	while(!q.empty())
    	{
    		int now=q.front();q.pop();
    		for(int i=0;i<10;i++)
    		{
    			if(!a[now].vis[i])
    			{
    				a[now].vis[i]=a[a[now].fail].vis[i];
    			}
    			else
    			{
    				a[a[now].vis[i]].fail=a[a[now].fail].vis[i];
    				a[a[now].vis[i]].end|=a[a[a[now].fail].vis[i]].end;
    				q.push(a[now].vis[i]);
    			}
    		}
    	}
    }
    int main()
    {
    	scanf("%s",t+1);
    	m=strlen(t+1);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%s",s),build(s);
    	getfail();
    	for(int i=0;i<m;i++)
    	{
    		for(int j=0;j<=cnt;j++)
    		{
    			if(!j)
    			{
    				if(!i)
    				{
    					int x=t[i+1]-'0';
    					for(int k=1;k<x;k++)
    					{
    						if(!a[a[j].vis[k]].end)
    						{
    							f[1][i+1][a[j].vis[k]]+=1;
    							f[1][i+1][a[j].vis[k]]%=mod;
    						}
    					}
    					if(!a[a[j].vis[x]].end)
    					{
    						f[0][i+1][a[j].vis[x]]+=1;
    						f[0][i+1][a[j].vis[x]]%=mod;
    					}
    				}
    				else
    				{
    					for(int k=1;k<=9;k++)
    					{
    						if(!a[a[j].vis[k]].end)
    						{
    							f[1][i+1][a[j].vis[k]]++;
    							f[1][i+1][a[j].vis[k]]%=mod;
    						}
    					}
    				}
    			}
    			if(f[0][i][j])
    			{
    				int x=t[i+1]-'0';
    				for(int k=0;k<x;k++)
    				{
    					if(!a[a[j].vis[k]].end)
    					{
    						f[1][i+1][a[j].vis[k]]+=f[0][i][j];
    						f[1][i+1][a[j].vis[k]]%=mod;
    					}
    				}
    				if(!a[a[j].vis[x]].end)
    				{
    					f[0][i+1][a[j].vis[x]]+=f[0][i][j];
    					f[0][i+1][a[j].vis[x]]%=mod;
    				}
    			}
    			if(f[1][i][j])
    			{
    				for(int k=0;k<=9;k++)
    				{
    					if(!a[a[j].vis[k]].end)
    					{
    						f[1][i+1][a[j].vis[k]]+=f[1][i][j];
    						f[1][i+1][a[j].vis[k]]%=mod;
    					}
    				}
    			}
    		}
    	}
    	for(int i=0;i<=cnt;i++)
    	{
    		ans+=f[0][m][i];
    		ans%=mod;
    		ans+=f[1][m][i];
    		ans%=mod;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

     小结:我们在处理字符串问题的时候脑子里先有几个数据结构在搞事情.. ...

  • 相关阅读:
    【HDOJ】2267 How Many People Can Survive
    【HDOJ】2268 How To Use The Car
    【HDOJ】2266 How Many Equations Can You Find
    【POJ】2278 DNA Sequence
    【ZOJ】3430 Detect the Virus
    【HDOJ】2896 病毒侵袭
    求奇数的乘积
    平方和与立方和
    求数列的和
    水仙花数
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9278438.html
Copyright © 2011-2022 走看看