P3311 [SDOI2014]数数 AC自动机+数位dp

https://www.luogu.org/problemnew/show/P3311

题意都是中文的,相信大家都很清楚

这道题我最开始以为是矩阵快速幂。。。但不过发现第一位不能是零,题目是小于N的,这样好像并不好弄。

既然与数的位数有关就用数位dp吧,其实数位dp我也忘了怎么写。

首先建立AC自动机,然后dp[pos][j]表示第pos位和自动机上j位的匹配数,然后直接枚举相加就可以了,这种做法枚举的是几位数的情况,比如枚举两位数有多少种,一位数有多少种,所以不能从0开始的,所以不需要从0开始枚举,(其实我刚刚也不知道怎么回事,把这个改了就过了)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1510;
struct Aho_Trie
{
    int nxt[N][26],fail[N],endd[N];
    int l,root;
    int newnode()
    {
        endd[l]=fail[l]=0;
        memset(nxt[l],0,sizeof(nxt[l]));
        return l++;
    }
    void init()
    {
        l=0;
        root=newnode();
    }
    void Insert(char *s)
    {
        int len=strlen(s);
        int u=root;
        for(int i=0;i<len;i++)
        {
            int x=s[i]-'0';
            if(!nxt[u][x]) nxt[u][x]=newnode();
            u=nxt[u][x];
        }
        endd[u]=1;
    }
    void build()
    {
        queue<int>qu;
        for(int i=0;i<10;i++)
            if(nxt[root][i]) qu.push(nxt[root][i]);
        while(!qu.empty())
        {
            int u=qu.front();qu.pop();
            for(int i=0;i<10;i++)
            {
                if(nxt[u][i]!=0) fail[nxt[u][i]]=nxt[fail[u]][i],qu.push(nxt[u][i]);
                else nxt[u][i]=nxt[fail[u]][i];
            }
        }
    }
}ac;
char s[N],tmp[N];
ll dp[N][N];
int len;
ll dfs(int pos,int x,bool limit)
{
    if(ac.endd[x]==1) return 0;
    if(pos==len-1) return 1;
    if(!limit&&dp[pos][x]!=-1) return dp[pos][x];
    ll ret=0;
    int up=limit?(s[pos+1]-'0'):9;
    for(int i=0;i<=up;i++)
    {
        ret+=dfs(pos+1,ac.nxt[x][i],limit&&i==up);
        ret%=mod;
    }
    if(!limit) dp[pos][x]=ret;
    return ret;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>s;
    int n;cin>>n;
    ac.init();
    for(int i=1;i<=n;i++)
    {
        cin>>tmp;
        ac.Insert(tmp);
    }
    ac.build();
    //ac.nxt[0][0]=0;
    memset(dp,-1,sizeof(dp));
    len=strlen(s);
    ll ans=0;
    for(int i=0;i<len;i++)
    {
        int x=(i==0)?(s[i]-'0'):9;
        for(int j=1;j<=x;j++)
        {
            //if(i==0&&j==0) continue;
            ans+=dfs(i,ac.nxt[0][j],i==0&&j==s[0]-'0');
            ans%=mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/89598455