zoukankan      html  css  js  c++  java
  • ZOJ3494 BCD Code [AC自动机+DP]

      比较恶心的一道题,主要在数位DP那里调试了好久。

      题目大意:0~9可以用对应的BCD码表示,给出A~B之间的十进制数,将他们化成BCD码的形式。但有些01串是不能出现的,求能化成BCD码的数的个数。

      先建图,然后将二进制转十进制,比如next[p][7]=next[p][0]->[1]->[1]->[1],如果后面这条路能走出来next[p][7]就存在,否则为-1。之后数位DP,求能走出的比X的小的数有多少种,这里要注意细节,很容易写错。求出后DP(B)-DP(A)就行了。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <algorithm>
      4 #define MAXN 2001
      5 #define MOD 1000000009
      6 typedef long long LL;
      7 int cas,n;
      8 char s[205];
      9 int next[MAXN][2],fail[MAXN],flag[MAXN],pos;
     10 int nextd[MAXN][10];
     11 int newnode(){
     12     next[pos][0]=next[pos][1]=0;
     13     fail[pos]=flag[pos]=0;
     14     return pos++;
     15 }
     16 void insert(char *s){
     17     int p=0;
     18     for(int i=0;s[i];i++){
     19         int &x=next[p][s[i]-'0'];
     20         p=x?x:x=newnode();
     21     }
     22     flag[p]=1;
     23 }
     24 int q[MAXN],front,rear;
     25 void makenext(){
     26     q[front=rear=0]=0,rear++;
     27     while(front<rear){
     28         int u=q[front++];
     29         for(int i=0;i<2;i++){
     30             int v=next[u][i];
     31             if(v==0)next[u][i]=next[fail[u]][i];
     32             else q[rear++]=v;
     33             if(u&&v)flag[v]|=flag[fail[v]=next[fail[u]][i]];
     34         }
     35     }
     36 }
     37 
     38 //d[i][j]表示第i个点之后长度为j的单词有多少种
     39 //注意只有在非第一位并且无限制时才能记忆化搜索
     40 LL d[MAXN][201];
     41 //limit表示是否有限制,first表示该位的下限,第一位为1,其它为0
     42 LL dp(int u,int l,int limit,int first){
     43     if(first==0&&limit==0&&d[u][l]!=-1)return d[u][l];
     44     if(l==0)return 1;
     45     LL tmp=0;
     46     //该位的上限
     47     int last=limit?s[l-1]-'0':9;
     48     for(int i=first;i<=last;i++){
     49         int v=nextd[u][i];
     50         if(v==-1)continue;
     51         tmp+=dp(v,l-1,limit&&last==i,0);
     52         if(tmp>MOD)tmp-=MOD;
     53     }
     54     if(limit==0)d[u][l]=tmp;
     55     return tmp;
     56 }
     57 LL solve(char *s){
     58     //更改字符串顺序便于DP并去掉头部的0
     59     int len=strlen(s);
     60     for(int i=0;i<len/2;i++)std::swap(s[i],s[len-i-1]);
     61     while(len>1&&s[len-1]=='0')len--;
     62     LL ans=0;
     63     //枚举长度从1~len的串,只有当长度为Len时是有限制的
     64     for(int i=len;i>=1;i--){
     65         ans+=dp(0,i,i==len,1);
     66         if(ans>MOD)ans-=MOD;
     67     }
     68     return ans;
     69 }
     70 //将二进制转换成10进制,nextd表示每个点后可走的10进制数
     71 int getnext(int p,int x){
     72     if(flag[p])return -1;
     73     for(int i=3;i>=0;i--){
     74         p=next[p][((x>>i)&1)?1:0];
     75         if(flag[p])return -1;
     76     }
     77     return p;
     78 }
     79 void makenextd(){
     80     for(int u=0;u<pos;u++)
     81         for(int i=0;i<10;i++)
     82             nextd[u][i]=getnext(u,i);
     83 }
     84 int main(){
     85 //freopen("test.in","r",stdin);
     86     scanf("%d",&cas);
     87     while(cas--){
     88         scanf("%d",&n);
     89         pos=0;newnode();
     90         while(n--){
     91             scanf("%s",s);
     92             insert(s);
     93         }
     94         makenext();
     95         makenextd();
     96         scanf("%s",s);
     97 
     98         //找比当前字符串小1的数
     99         int len=strlen(s);
    100         for(int i=len-1;i>=0;i--){
    101             if(s[i]!='0'){s[i]--;break;}
    102             else s[i]='9';
    103         }
    104         memset(d,-1,sizeof d);
    105         LL ans=-solve(s);
    106         scanf("%s",s);
    107         ans+=solve(s);
    108         printf("%lld\n",(ans%MOD+MOD)%MOD);
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    python中True,False,数值之间用<,>,==进行比较规则
    分析python代码性能的程序分析包cProfile
    /bin/bash^M: bad interpreter: No such file or directory问题
    架构图以及vue的简介
    重写简易的confirm函数
    CSS绝对定位元素居中的几种方法
    Linux 部署java web 项目,验证码图片不显示文字问题
    log4j升级到log4j2
    openssh一键升级脚本(只升级openssh,其它已有环境不变,解决root登录问题)
    openssh一键升级脚本(测试成功)
  • 原文地址:https://www.cnblogs.com/swm8023/p/2637252.html
Copyright © 2011-2022 走看看