zoukankan      html  css  js  c++  java
  • [BZOJ3530][SDOI2014]数数

    BZOJ
    Luogu

    sol

    AC自动机做数位(DP)。首先位数小于(n)的位数的数只要满足没有不合法串即可,记(f_{i,j})表示填了(i)个数,当前在(AC)自动机上编号为(j)的节点上的方案数,取答案(sum_{i=1}^{n-1}sum_{j=0}^{tot}f_{i,j})。注意转移的时候是只能转移到自己(Trie)图上的儿子而不是儿子通过(fail)指针串起来的所有点。
    位数等于(n)的,在前面那个状态上多加一维,表示是否已经严格小于那个数,然后按照数位(DP)的一般思路卡一卡就好了。

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int mod = 1e9+7;
    const int N = 2005;
    int gi()
    {
        int x=0,w=1;char ch=getchar();
        while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if (ch=='-') w=0,ch=getchar();
        while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return w?x:-x;
    }
    
    int n,m,l,tot,ch[10][N],fail[N],frb[N],dp[2][N][N],ans;
    char s[N],c[N];
    queue<int>Q;
    void Insert()
    {
        scanf("%s",c);l=strlen(c);
        int x=0;
        for (int i=0;i<l;i++)
        {
            if (!ch[c[i]-'0'][x]) ch[c[i]-'0'][x]=++tot;
            x=ch[c[i]-'0'][x];
        }
        frb[x]=1;
    }
    void Get_Fail()
    {
        for (int i=0;i<10;i++) if (ch[i][0]) Q.push(ch[i][0]);
        while (!Q.empty())
        {
            int u=Q.front();Q.pop();
            for (int i=0;i<10;i++)
                if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],Q.push(ch[i][u]);
                else ch[i][u]=ch[i][fail[u]];
            frb[u]|=frb[fail[u]];
        }
    }
    void DP()
    {
        dp[0][0][0]=1;
        for (int i=0;i<n;i++)
            for (int j=0;j<=tot;j++)
                if (!frb[j])
                    for (int k=0;k<10;k++)
                        if (i+k&&!frb[ch[k][j]])
                            (dp[0][i+1][ch[k][j]]+=dp[0][i][j])%=mod;
        for (int i=1;i<n;i++)
            for (int j=0;j<=tot;j++)
                (ans+=dp[0][i][j])%=mod;
        memset(dp,0,sizeof(dp));
        dp[1][0][0]=1;
        for (int i=0;i<n;i++)
            for (int j=0;j<=tot;j++)
                if (!frb[j])
                    for (int k=0;k<10;k++)
                        if (i+k&&!frb[ch[k][j]])
                        {
                            (dp[0][i+1][ch[k][j]]+=dp[0][i][j])%=mod;
                            if (k==s[i+1]-'0') (dp[1][i+1][ch[k][j]]+=dp[1][i][j])%=mod;
                            if (k<s[i+1]-'0') (dp[0][i+1][ch[k][j]]+=dp[1][i][j])%=mod;
                        }
        for (int j=0;j<=tot;j++) (ans+=(dp[0][n][j]+dp[1][n][j])%mod)%=mod;
    }
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);
        scanf("%d",&m);
        for (int i=1;i<=m;i++) Insert();
        Get_Fail();
        DP();
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    2015第11周日
    2015第11周六
    素数推断算法(高效率)
    vc中关于 directx的配置,和dxsdk_extras(directshow)
    几种开源分词工具的比較
    javascript实现函数的默认參数值方法
    MyReport报表引擎2.0.0.0新功能
    怎样在小方框上打对号 小方框内打对勾 word 方框打对勾
    Bombing HDU, 4022(QQ糖的消法)
    fullcalendar日历控件知识点集合
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8350090.html
Copyright © 2011-2022 走看看