• [SDOI2014] 数数


    给定一个长度为 (l) 的大数 (n),求 (leq n) 且不以子串形式包含给定 (m) 字典的数的个数。(lleq 1200, mleq 100, sum len leq 1500)

    Solution

    (f[i][j][0/1]) 表示考虑了前 (i) 位,走到 (j) 结点,下一个字符是否挨着上界的方案数

    转移方法有

    • (f[i-1][j][0] o f[i][ch[j][0..9]][0])
    • (f[i-1][j][1] o f[i][ch[j][0..s[i]-1]][0])
    • (f[i-1][j][1] o f[i][ch[j][s[i]]][1])

    但是考虑到数字中不能有前导零但是字典中可以有

    据说只需要大力删除 (ch[0][0]) 就可以解决该问题(大雾)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5005;
    const int mod = 1e+9 + 7;
    #define ch c
    queue <int> q;
    int n,m,c[N][10],f[N][N][2],val[N],fi[N],cnt,ans[1005];
    
    void ins(char *str,int id) {
        int len=strlen(str), p=0;
        for(int i=0; i<len; i++) {
            int v=str[i]-'0';
            if(!c[p][v]) c[p][v]=++cnt;
            p=c[p][v];
        }
        val[p]=id;
    }
    void build() {
        for(int i=0; i<10; i++) if(c[0][i]) fi[c[0][i]]=0, q.push(c[0][i]);
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=0; i<10; i++)
                if(c[u][i]) fi[c[u][i]]=c[fi[u]][i], q.push(c[u][i]);
                else c[u][i]=c[fi[u]][i];
        }
    }
    
    char str[N],pat[N];
    
    void sh(int &x,int y) {
        x=(x+y)%mod;
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>str;
        n=strlen(str);
        cin>>m;
        for(int i=1;i<=m;i++) {
            cin>>pat;
            ins(pat,i);
        }
        build();
        ch[0][0]=0;
        for(int i=1;i<str[0]-'0';i++) sh(f[1][ch[0][i]][0],1);
        sh(f[1][ch[0][str[0]-'0']][1],1);
        for(int i=2;i<=n;i++) {
            for(int j=1;j<10;j++) sh(f[i][ch[0][j]][0],1);
            for(int j=0;j<=cnt;j++) if(val[j]==0) {
                for(int k=0;k<=9;k++) {
                    if(val[ch[j][k]]==0) sh(f[i][ch[j][k]][0],f[i-1][j][0]);
                }
                for(int k=0;k<str[i-1]-'0';k++) {
                    if(val[ch[j][k]]==0) sh(f[i][ch[j][k]][0],f[i-1][j][1]);
                }
                if(val[ch[j][str[i-1]-'0']]==0)
                    sh(f[i][ch[j][str[i-1]-'0']][1],f[i-1][j][1]);
            }
        }
        int ans=0;
        for(int i=0;i<=cnt;i++) if(val[i]==0) sh(ans,f[n][i][0]+f[n][i][1]);
        cout<<ans;
    }
    
    
  • 相关阅读:
    使用TransactionScope实现多数据库连接事务操作
    zabbix_agentlinux下的安装
    (转)Zabbix AgentWindows平台配置指导
    使用SpringSide 3.1.4.3开发Web项目的全过程(上)
    应用开发中数据字典项设计实现方案
    Oracle Top N 和 Oracle中的limit问题解决方案
    Struts 2.0的codebehinde插件应用简述
    PropertyUtils和MethodUtils使用
    Log4j基本使用方法
    Quartz从入门到进阶
  • 原文地址:https://www.cnblogs.com/mollnn/p/12453627.html
Copyright © 2020-2023  润新知