P3311 [SDOI2014]数数

news/2024/7/6 21:00:44

思路

看到多个子串并且不能包含的情况,想到了AC自动机
但是题目多了一个不能大于给出的n的限制条件,联想数位dp的过程,设f[i][j][0/1]表示在第i位,AC自动机的第j个节点,数位有/无限制的方案数
dp方程就是对应的转移到子节点即可,不向有标记的节点转移

注意如果跳fail能够跳到限制节点,就也不能转移,因为fail树上的父节点是子节点的子串,如果父节点是单词节点,子节点一定包含单词
另外题目中的数不能出现前导零,所以从根节点向子节点转移时不能转移到根的0号子节点

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define int long long
const int MOD = 1000000007;
using namespace std;
int trie[1501][10],Nodecnt,fail[1501],mark[1501],root,f[1201][1501][2],lens,lent;
char s[1501],t[1501];
void insert(char *s,int len){
    int o=root;
    for(int i=1;i<=len;i++){
        if(!trie[o][s[i]-'0'])
            trie[o][s[i]-'0']=++Nodecnt;
        o=trie[o][s[i]-'0'];
    }
    mark[o]++;
}
void get_fail(void){                                    
    queue<int> q;
    for(int i=0;i<10;i++){
        if(trie[root][i]){
            fail[trie[root][i]]=root;
            q.push(trie[root][i]);
        }
    }
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<10;i++){
            if(trie[x][i]){
                fail[trie[x][i]]=trie[fail[x]][i];
                // mark[trie[x][i]]|=mark[trie[fail[x]][i]];
                q.push(trie[x][i]);
            }
            else{
                trie[x][i]=trie[fail[x]][i];
            }
        }
    }
}
void getban(void){
    for(int i=0;i<=Nodecnt;i++){
        int p=i;
        for(;p;p=fail[p])
            if(mark[p]){
                mark[i]=true;
                break;
            }    
    }
}
int dp(void){
    for(int i=0;i<lens;i++){
        for(int j=0;j<=Nodecnt;j++){
                if(f[i][j][0]){
                    for(int k=0;k<s[i+1]-'0';k++)
                        if(!mark[trie[j][k]])
                            f[i+1][trie[j][k]][1]=(f[i+1][trie[j][k]][1]+f[i][j][0])%MOD;
                    if(!mark[trie[j][s[i+1]-'0']])
                        f[i+1][trie[j][s[i+1]-'0']][0]=(f[i+1][trie[j][s[i+1]-'0']][0]+f[i][j][0])%MOD;
                }
                if(f[i][j][1]){
                    for(int k=0;k<10;k++)
                        if(!mark[trie[j][k]])
                            f[i+1][trie[j][k]][1]=(f[i+1][trie[j][k]][1]+f[i][j][1])%MOD;
                }
                if(!j){
                    if(!i){
                        for(int k=1;k<s[i+1]-'0';k++)
                            if(!mark[trie[j][k]])
                                f[i+1][trie[j][k]][1]=(1+f[i+1][trie[j][k]][1])%MOD;
                        if(!mark[trie[j][s[i+1]-'0']])
                            f[i+1][trie[j][s[i+1]-'0']][0]=(1+f[i+1][trie[j][s[i+1]-'0']][0])%MOD;
                    }
                    else{
                        for(int k=1;k<10;k++)
                            if(!mark[trie[j][k]])
                                f[i+1][trie[j][k]][1]=(1+f[i+1][trie[j][k]][1])%MOD;
                    }
                }
            }
        }
    int ans=0;  
    for(int i=0;i<=Nodecnt;i++)
        ans=(f[lens][i][0]+f[lens][i][1]+ans)%MOD;
    return ans;
}
signed main(){
    scanf("%s",s+1);
    lens=strlen(s+1);
    int n;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",t+1);
        lent=strlen(t+1);
        insert(t,lent);
    }
    get_fail();
    getban();
    // for(int i=1;i<=Nodecnt;i++)
    //     if(mark[i])
    //         printf("%d!\n",i);
    printf("%lld\n",dp());
    return 0;
}

转载于:https://www.cnblogs.com/dreagonm/p/10459643.html


http://www.niftyadmin.cn/n/2745322.html

相关文章

内存管理之2:x86页式内存管理

2019独角兽企业重金招聘Python工程师标准>>> date: 2014-09-04 19:09 内存管理的目的是什么&#xff1f;内存管理本身就像一个外观模式&#xff0c;它隐藏底层细节而给应用程序提供一个统一易用的访问内存的接口。程序可以访问4G空间中的任意地址&#xff0c;但实际…

啊撒擦上去

/* 题目内容&#xff1a;在大学期间&#xff0c;经常需要租借教室。大到院系举办活动&#xff0c;小到学习小组自习讨论&#xff0c;都需要向学校申请借教室。教室的大小功能不 同&#xff0c;借教室人的身份不同&#xff0c;借教室的手续也不一样。面对海量租借教室的信息&…

产妇坐月子里可以吃哪些水果?

产妇坐月子里可以吃哪些水果? 众所周知&#xff0c;生果的营养丰厚&#xff0c;滋味鲜美&#xff0c;人人爱吃。但是生果是生冷的食物&#xff0c;产妇吃了会怕着凉吗?专业的月子中心提示&#xff0c;产妇恰当吃些生果&#xff0c;不仅能添加营养&#xff0c;协助消化&#x…

功能性组件和Classes有什么不同?

React函数组件与React类有何不同&#xff1f; 有一段时间&#xff0c;规范的答案是类可以访问更多功能&#xff08;如状态&#xff09;。但是自从有了Hook后&#xff0c;这个答案变得不唯一了。 也许你听说其中一个表现更好。哪一个&#xff1f;许多此类基准都存在缺陷&#xf…

PHP代码常用注释规范(PHP Doc)

PHP代码常用注释规范&#xff08;PHP Doc&#xff09; 介绍几个常用的PHP注释 在PHP文件中使用该注释格式开始进行文件注释&#xff1a; /*** author 作者* copyright 版权信息* version 版本* 等等*/ 复制代码 描述一个类的注释&#xff1a; /*** Class 类名* package 命名空间…

Ruby 2.6.3 发布,引入日本新年号“令和”

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; Ruby 2.6.3 已发布。新版本引入了新的日本年号&#xff1a;“令和”&#xff08;Reiwa&#xff09;。 主要更新内容&#xff1a; 升级支持的 Unicode 版本至 12.1 beta&#xff08;#15195&#…

留学目的地选择之内华达州

留学目的地选择之内华达州 美国大学奖学金专家介绍到&#xff1a;内华达州(Nevada)是美国西部的一个州&#xff0c;北接俄勒冈州和爱达荷州&#xff0c;东界犹他州&#xff0c;东南邻亚利桑那州&#xff0c;西部与加利福尼亚州接壤。又称北美艾灌木丛州&#xff0c;以其发达的赌…

php课程 11-37 类和对象的关系是什么

php课程 11-37 类和对象的关系是什么 一、总结 一句话总结&#xff1a;类生成对象&#xff0c;对象是类的实例化&#xff0c;一定是先有类&#xff0c;后有对象&#xff0c;一定是先有标准&#xff0c;再有个体。 1、oop的三大优势是什么&#xff1f; 重用性&#xff0c;灵活性…