码迷,mamicode.com
首页 > 其他好文 > 详细

SDOI2014 数数

时间:2019-02-17 22:07:50      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:using   std   long   ref   include   clu   处理   长度   动态   

题目链接:戳我

AC自动机+动态规划。

我们设\(dp[1/2/3][i][j]\)来表示不同的状态,i表示处理到文本串第i位,j表示处理到AC自动机上节点j。

因为这道题有前导零,所以我们可以参考一下数位DP的思想,我们区分有限制和没有限制的情况分类套路进行AC自动机上DP。

3表示没有任何限制的DP。当当前处理的字符串长度小于文本串长度的时候,显然我们可以累积合法答案。
\(dp[3][ac[now].t[k]+=dp[3][i][now]\)

2表示有限制的DP。当前处理的字符串等于当前文本串的长度。当前处理位已经达到限制,显然上一位也应当达到限制。我们应当从上一位达到最大限制的状态转移而来。

1也表示有限制的DP。当前处理的字符串等于当前文本串的长度。当前处理位没有达到限制,所以有两种转移方法,一种是从上一个合法的自己转移而来,一种是从2转移而来。

具体转移可以参考代码。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#define MAXN 2000
#define mod 1000000007
using namespace std;
int n,cnt,lenth;
int dp[4][MAXN][MAXN];
long long ans;
char s[MAXN],N[MAXN];
struct Node{int fail,end,t[11];}ac[MAXN*100];
inline void build(char x[])
{
    int len=strlen(x+1),now=0;
    for(int i=1;i<=len;i++)
    {
        if(ac[now].t[x[i]-'0']==0)
            ac[now].t[x[i]-'0']=++cnt;
        now=ac[now].t[x[i]-'0'];
    }
    ac[now].end=1;
}
inline void get_fail()
{
    queue<int>q;
    for(int i=0;i<=9;i++)
        if(ac[0].t[i]!=0)
            ac[ac[0].t[i]].fail=0,q.push(ac[0].t[i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        ac[u].end|=ac[ac[u].fail].end;
        for(int i=0;i<=9;i++)
        {
            if(ac[u].t[i]!=0)
            {
                ac[ac[u].t[i]].fail=ac[ac[u].fail].t[i];
                q.push(ac[u].t[i]);
            }
            else ac[u].t[i]=ac[ac[u].fail].t[i];
        }

    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
#endif
    scanf("%s",N+1);
    lenth=strlen(N+1);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        build(s);
    }
    get_fail();
    dp[3][0][0]=dp[2][0][0]=1;
    for(int i=0;i<lenth;i++)
    {
        for(int j=0;j<=cnt;j++)
        {
            if(ac[j].end!=0) continue;
            for(int k=0;k<=9;k++)
            {
                if(!ac[ac[j].t[k]].end)
                {
                    if(i==0&&k==0) continue;
                    dp[3][i+1][ac[j].t[k]]=(dp[3][i+1][ac[j].t[k]]+dp[3][i][j])%mod;
                }
            }
        }
    }
    for(int i=0;i<lenth;++i)
        for(int u=0;u<=cnt;++u)
            if(!ac[u].end)
            {
                for(int k=0;k<=9;++k)
                    if(!ac[ac[u].t[k]].end)
                    {
                        if(!i&&!k) continue;
                        (dp[1][i+1][ac[u].t[k]]+=dp[1][i][u])%=mod;
                        if(k<N[i+1]-48)(dp[1][i+1][ac[u].t[k]]+=dp[2][i][u])%=mod;
                        if(k==N[i+1]-48)(dp[2][i+1][ac[u].t[k]]+=dp[2][i][u])%=mod;
                    }
            }
    for(int i=1;i<lenth;i++)
        for(int j=0;j<=cnt;j++)
            ans=(ans+dp[3][i][j])%mod;
    for(int i=0;i<=cnt;i++)
        ans=(ans+dp[1][lenth][i])%mod,ans=(ans+dp[2][lenth][i])%mod;
    printf("%lld\n",ans);
}

SDOI2014 数数

标签:using   std   long   ref   include   clu   处理   长度   动态   

原文地址:https://www.cnblogs.com/fengxunling/p/10392837.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!