• BZOJ3530:[SDOI2014]数数(AC自动机,数位DP)


    Description

    我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
    给定N和S,计算不大于N的幸运数个数。

    Input

    输入的第一行包含整数N。
    接下来一行一个整数M,表示S中元素的数量。
    接下来M行,每行一个数字串,表示S中的一个元素。

    Output

    输出一行一个整数,表示答案模109+7的值。

    Sample Input

    20
    3
    2
    3
    14

    Sample Output

    14

    HINT

    下表中l表示N的长度,L表示S中所有串长度之和。

    1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500

    Solution

    一个挺简单的一个题……建出来$AC$自动机然后在上面直接跑数位$DP$就好了。只不过有点小地方需要注意。

    用$DFS(zero,lim,pos,now)$是否有前导0,是否卡上界,第$pos$位,自动机上第$now$个点。

    为什么要存前导0呢?我们可以发现有这么一个例子:

    10

    1

    01

    这个跑出来应该是10,然而不记前导零特判一下会跑出来9。这是因为当幸运串为01的时候我们会忽略前导0,所以是合法的。

    只需要在$DFS$的时候特判一下,如果有前导0,且幸运数这一位选0,且$now$还在根节点,就让$now$停在根节点就好了。

    建立AC自动机的时候,如果某个节点能够沿着fail指针跳到单词节点,那么这个节点也应当禁止通过……

    自测一时爽

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<queue>
     5 #define N (1509)
     6 #define MOD (1000000007)
     7 using namespace std;
     8 
     9 int sz,Son[N][11],Fail[N],End[N];
    10 int cnt,m,x,f[N][N],a[N],spc[N];
    11 char n[N],s[N];
    12 queue<int>q;
    13 
    14 void Insert(char s[])
    15 {
    16     int now=0;
    17     for (int i=0,l=strlen(s); i<l; ++i)
    18     {
    19         int c=s[i]-'0';
    20         if (!Son[now][c]) Son[now][c]=++sz;
    21         now=Son[now][c];
    22     }
    23     End[now]++;
    24 }
    25 
    26 void Build_Fail()
    27 {
    28     for (int i=0; i<=9; ++i)
    29         if (Son[0][i]) q.push(Son[0][i]);
    30     while (!q.empty())
    31     {
    32         int now=q.front(); q.pop();
    33         for (int i=0; i<=9; ++i)
    34         {
    35             if (!Son[now][i])
    36             {
    37                 Son[now][i]=Son[Fail[now]][i];
    38                 continue;
    39             }
    40             Fail[Son[now][i]]=Son[Fail[now]][i];
    41             q.push(Son[now][i]);
    42         }
    43     }
    44 }
    45 
    46 int DFS(int zero,int lim,int pos,int now)
    47 {
    48     if (pos==0) return 1;
    49     if (!zero && !lim && f[pos][now]!=-1) return f[pos][now];
    50     f[pos][now]=0;
    51     int up=lim?n[pos]-'0':9;
    52     for (int i=0; i<=up; ++i)
    53         if (!End[Son[now][i]])
    54         {
    55             if (zero && !i && !now) (f[pos][now]+=DFS(zero,lim&&0==up,pos-1,0))%=MOD;
    56             else
    57             {
    58                 int flag=1,t=Son[now][i];
    59                 while (t)
    60                 {
    61                     if (End[t]) {flag=0; break;}
    62                     t=Fail[t];
    63                 }
    64                 if (!flag) continue;
    65                 (f[pos][now]+=DFS(zero&&!i,lim&&i==up,pos-1,Son[now][i]))%=MOD;
    66             }
    67         }
    68     return f[pos][now];
    69 }
    70 
    71 int main()
    72 {
    73     memset(f,-1,sizeof(f));
    74     scanf("%s%d",n+1,&m); cnt=strlen(n+1);
    75     for (int i=1; i<=m; ++i)
    76         scanf("%s",s),Insert(s);
    77     Build_Fail(); 
    78     for (int i=1,j=cnt; i<j; ++i,--j)
    79         swap(n[i],n[j]);
    80     printf("%d
    ",DFS(1,1,cnt,0)-1);
    81 }
  • 相关阅读:
    [System.currentTimeMillis]/[Calendar.getInstance().getTimeInMillis()]/[new Date().getTime()]
    [Maven]告警[WARNING] Unable to create Maven project from repository.
    通过设置JDK解决存在多个Gradle后台进程的问题
    使用OpenSSL实现X25519秘钥协商功能
    C++代码质量度量工具大阅兵
    Java代码质量度量工具大阅兵
    计算两个时间的时间差(天、小时、分钟、秒数)
    上传文件进度条 (已上传大小、总大小、速度、剩余时间、已用时间)
    table 表格自适应
    谷歌浏览器input框添加了黄色 背景色
  • 原文地址:https://www.cnblogs.com/refun/p/10037975.html
Copyright © 2020-2023  润新知