• 【题解】SDOI2014数数


    真的很开心呢,总算是有一道完完全全由自己做出来的题目啦~

    这一道题目洛谷P3311和另一道JSOI文本生成器的题目是十分相像的,dp方面几乎相同。只是<=n的约束,让这道题目必须结合数位dp的方法,新建一个维度代表之后数字的大小是否受到限制。0代表受限,1代表不受限。但是处理前导零的部分的确较为头痛,最后采取的方法是在第一次dp的时候不允许有前导零的存在,在第二次dp的时候才把这一部分的答案统计出来。所以在第二次的dp转移中,一个节点只能由父亲节点、而不能由Fail节点转移而来。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 2000
    #define mod 1000000007
    int m, cnt = 1, len, ans, ch[maxn][10], dp[maxn][maxn][2], fail[maxn];
    bool error[maxn];
    string n, s;
    struct AC_Automation
    {
        void Trie_ins()
        {
            int now = 1, len = s.length(); 
            for(int i = 0; i < len; i ++)
            {
                if(!ch[now][s[i] - '0']) ch[now][s[i] - '0'] = ++ cnt;
                now = ch[now][s[i] - '0'];
            }
            error[now] = true;
        }
        
        void AC_build()
        {
            queue <int> q;
            q.push(1);
            while(!q.empty())
            {
                int u = q.front();
                q.pop();
                for(int i = 0; i < 10; i ++)
                {
                    if(ch[u][i])
                    {
                        int v = ch[u][i], k = fail[u];
                        while(!ch[k][i]) k = fail[k];
                        fail[v] = ch[k][i];
                        if(error[fail[v]]) error[v] = true;
                        q.push(v);
                    }
                    else ch[u][i] = ch[fail[u]][i];
                }
            }
        }
    }ACM;
    
    void DP(int x)
    {
        for(int i = 1; i <= cnt; i ++)
        {
            if(error[i] || (!dp[x - 1][i][0] && !dp[x - 1][i][1])) continue;
            for(int j = 0; j < 10; j ++)
            {
                if(x == 1 && j == 0) continue;
                int k = i;
                while(!ch[k][j]) k = fail[k];
                int v = ch[k][j];
                if(j == n[x - 1] - '0') dp[x][v][0] = (dp[x][v][0] + dp[x - 1][i][0]) % mod;
                if(j < n[x - 1] - '0') dp[x][v][1] = (dp[x][v][1] + dp[x - 1][i][0]) % mod;
                dp[x][v][1] = (dp[x][v][1] + dp[x - 1][i][1]) % mod;
            }
        }
    }
    
    void DP2()
    {
        dp[0][1][1] = 1;
        for(int x = 1; x < len; x ++)
            for(int i = 1; i <= cnt; i ++)
            {
                if(error[i] || !dp[x - 1][i][1]) continue;
                for(int j = 0; j < 10; j ++)
                {
                    if(x == 1 && j == 0) continue;
                    int k = i;
                    int v = ch[k][j];
                    dp[x][v][1] = (dp[x][v][1] + dp[x - 1][i][1]) % mod;
                }
            }
        for(int i = 1; i < len; i ++)
            for(int j = 1; j <= cnt; j ++)
                if(!error[j]) ans = (ans + dp[i][j][1]) % mod;
    }
    
    int main()
    {
        cin >> n;
        cin >> m;
        for(int i = 0; i < 10; i ++) ch[0][i] = 1;
        for(int i = 1; i <= m; i ++)
        {
            cin >> s;
            ACM.Trie_ins();
        }
        ACM.AC_build();
        len = n.length();
        dp[0][1][0] = 1;
        for(int i = 1; i <= len; i ++) DP(i);
        for(int i = 1; i <= cnt; i ++)
            if(!error[i]) ans = (ans + dp[len][i][0] + dp[len][i][1]) % mod;
        memset(dp, 0, sizeof(dp));
        DP2();
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    201671010439-词频统计软件项目报告
    201671010439温永琴 实验三作业互评与改进
    读构建之法提出的问题
    实验十四 团队项目评审&课程学习总结
    201671010441 徐浩杰 实验四 附加实验 项目互评
    201671010441 徐浩杰《英文文本统计分析》结对项目报告
    201671010441徐浩杰 词频统计软件项目报告
    201671010441 徐浩杰 实验三作业互评与改进报告
    实验一 通读教材后提问
    实验十四 团队项目评审&课程学习总结
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8455500.html
Copyright © 2020-2023  润新知