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

    题意
    我们称一个正整数N((len(N) <= 1200))是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。给定N和S,计算不大于N的幸运数个数。
    题解
    (Trie)图上跑数位(dp)(dp[i][j]) 表示走了(i)步到了结点(j)的方案数,那么转移的时候分两种情况,①是已经沿着边界走了(i)步,②不是沿着边界走了(i)步。多想想数位(dp)的边界处理方式。然后顺着图转移就行了。从高位向低位枚举数位的过程中会产生前导0,这与{0},{00},{000}会产生冲突,所以是前导0并且当前枚举的 i == 0, 就直接回到根节点
    代码

    const int mod = 1000000007;
    
    struct node {
        bool flag;
        int fail, vis[10];
        node() {
            mem(vis, 0);
            flag = fail = 0;
        }
    };
    
    node a[2000];
    
    struct Acmation {
        int tot;
    
        stack<int> st;
    
        void Inite() {
            tot = 0;
        }
        void Insert(char *s) {
            int n = strlen(s);
            int now = 0;
            rep(i, 0, n) {
                int id = s[i] - '0';
                if (!a[now].vis[id]) a[now].vis[id] = ++tot;
                now = a[now].vis[id];
            }
            a[now].flag = 1;
        }
        void getFail() {
            queue<int> q;
            rep(i, 0, 10) if (a[0].vis[i]) {
                a[a[0].vis[i]].fail = 0;
                q.push(a[0].vis[i]);
            }
            while(!q.empty()) {
                int now = q.front();
                q.pop();
                rep(i, 0, 10) {
                    int pre = a[a[now].fail].vis[i];
                    if (a[now].vis[i]) {
                        a[a[now].vis[i]].fail = pre;
                        a[a[now].vis[i]].flag |= a[pre].flag;
                        q.push(a[now].vis[i]);
                    }
                    else a[now].vis[i] = pre;
                }
            }
        }
    };
    
    Acmation ac;
    
    char s[2000];
    int n, m, dp[1300][1600];
    
    int DFS(int pos, int now, bool limit, bool lead) {
        if (pos == n) return 1;
        if (!limit && !lead && dp[pos][now] != -1) return dp[pos][now];
    
        int up = (limit ? s[pos] - '0' : 9);
        int ans = 0;
    
        Rep(i, 0, up) {
            if (!i && lead) ans = (ans + DFS(pos + 1, 0, 0, 1)) % mod;
            else {
                if (a[a[now].vis[i]].flag) continue;
                ans = (ans + DFS(pos + 1, a[now].vis[i], limit && (i == up), lead && (i == 0))) % mod;
            }
        }
    
        if (!limit && !lead) dp[pos][now] = ans;
        return ans;
    }
    
    int main()
    {
        ac.Inite();
    
        scanf("%s", s);
        n = strlen(s);
    
        char str[2000];
    
        sc(m);
        Rep(i, 1, m) {
            scanf("%s", str);
            ac.Insert(str);
        }
    
        ac.getFail();
    
        mem(dp, -1);
        pr(DFS(0, 0, 1, 1) - 1);
    }
    
    
  • 相关阅读:
    MySQL主主同步方案
    Mysql增量备份与恢复
    配置合适的存储引擎
    基于Amoeba读写分离
    部署myaql主从异步复制
    MySQL完全备份操作
    echo 命令详解
    ELK 基本部署
    zabbix 简介
    基于 Git Tag 发布及回滚代码
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9733936.html
Copyright © 2011-2022 走看看