zoukankan      html  css  js  c++  java
  • ZOJ 3494

    超级神奇有趣题。

    AC自动机+数位DP。其实,数位DP在处理含有某些数字时特别不好处理,应该把它倒转为求不含有。这道题把数位DP+AC自动机结合起来,实在是很巧妙,把数字变为串来处理,强大!

    要使用AC自动机来处理数位DP,首先就是要确定哪些状态由当前状态开始是不可以到达的,有哪些是可以到达的。这是显而易见的,因为既然是数位DP,必定涉及到数字的问题,每改变一个数字就会到达自动机上的一个状态,确定哪些状态可达或不可达是很有必要的。这就要求要构建trie图了。

    其次就是DFS了,在进行DFS深搜前,要确定当前状态变更一个数字后的状态是否可达,再进行转移。

    在这题,要处理前导0的问题,因为0000(十进制)里,其实只代表一个0,但可能会出现禁止状态(如二进制连续五个0违法,但四个0不违法)。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define LL long long
      6 using namespace std;
      7 const LL MOD=1000000009;
      8 const int root=0;
      9 int trie[2010][2],tot,bit[210];
     10 int next[2010][10],fail[2010];
     11 bool tag[2010];
     12 char str[210];
     13 LL dp[210][2010];
     14 int que[2010],head,tail;
     15 
     16 void clr(int now){
     17     trie[now][0]=trie[now][1]=-1;
     18 }
     19 
     20 void insert(){
     21     int p=root,i=0,len=strlen(str);
     22     while(i++<len){
     23         if(trie[p][str[i-1]-'0']==-1){
     24             trie[p][str[i-1]-'0']=++tot;
     25             clr(tot);
     26         }
     27         p=trie[p][str[i-1]-'0'];
     28     }
     29     tag[p]=true;
     30 }
     31 
     32 void build_ac(){
     33     head=tail=0;
     34     que[tail++]=root;
     35     while(head!=tail){
     36         int tmp=que[head++];
     37         int p=-1;
     38         for(int i=0;i<2;i++){
     39             if(trie[tmp][i]!=-1){
     40                 if(tmp==root) fail[trie[tmp][i]]=root;
     41                 else{
     42                     p=fail[tmp];
     43                     while(p!=-1){
     44                         if(trie[p][i]!=-1){
     45                             fail[trie[tmp][i]]=trie[p][i];
     46                             break;
     47                         }
     48                         p=fail[p];
     49                     }
     50                     if(p==-1) fail[trie[tmp][i]]=root;
     51                 }
     52                 if(tag[fail[trie[tmp][i]]]) tag[trie[tmp][i]]=tag[fail[trie[tmp][i]]];
     53                 que[tail++]=trie[tmp][i];
     54             }
     55             else{  
     56                 if(tmp==root) trie[tmp][i]=root;
     57                 else{
     58                     p=fail[tmp];
     59                     while(p!=-1){
     60                         if(trie[p][i]!=-1){
     61                             trie[tmp][i]=trie[p][i];
     62                             break;
     63                         }
     64                         p=fail[p];
     65                     }
     66                     if(p==-1) trie[tmp][i]=root;
     67                 }
     68             }
     69         }
     70     }
     71 }
     72 
     73 void interval(){
     74     int len=strlen(str)-1;
     75     char tmp;
     76     for(int i=len;i>=len-i;i--){
     77         tmp=str[i];
     78         str[i]=str[len-i];
     79         str[len-i]=tmp;
     80     }
     81 }
     82 
     83 int cal_next(int p,int j){
     84     if(tag[p]) return -1;
     85     for(int k=3;k>=0;k--){
     86         p=trie[p][(j>>k)&1];
     87         if(tag[p]) return -1;
     88     }
     89     return p;
     90 }
     91 
     92 void Calculation(){
     93     for(int i=0;i<=tot;i++){
     94         for(int j=0;j<=9;j++){
     95             next[i][j]=cal_next(i,j);
     96         }
     97     }
     98 }
     99 
    100 LL dfs(int len,int j,bool limit,bool z){
    101     if(len==-1) return 1LL;
    102     if(!limit&&dp[len][j]!=-1) return dp[len][j];
    103     int up=limit?bit[len]:9;
    104     LL ans=0;
    105     if(z&&len>0){
    106         ans+=dfs(len-1,j,limit&&up==0,true);
    107     }
    108     else{
    109         if(next[j][0]!=-1&&!tag[next[j][0]])
    110         ans+=dfs(len-1,next[j][0],limit&&up==0,false);
    111     }
    112     for(int i=1;i<=up;i++){
    113         if(next[j][i]!=-1&&!tag[next[j][i]]){
    114             ans+=dfs(len-1,next[j][i],limit&&i==up,false);
    115         }
    116     }
    117     ans%=MOD;
    118     if(!limit) dp[len][j]=ans;
    119     return ans;
    120 }
    121 
    122 LL slove(){
    123     int len=strlen(str);
    124     len--;
    125     for(int i=len;i>=0;i--)
    126     bit[i]=str[i]-'0';
    127     return dfs(len,0,true,true);
    128 }
    129 
    130 int main(){
    131     int T,n,len;
    132     scanf("%d",&T);
    133     while(T--){
    134         memset(tag,false,sizeof(tag));
    135         memset(dp,-1,sizeof(dp));
    136         memset(fail,-1,sizeof(fail));
    137         scanf("%d",&n);
    138         tot=0;
    139         clr(root);
    140         for(int i=0;i<n;i++){
    141             scanf("%s",str);
    142     //        cout<<str<<endl;
    143             insert();
    144         }
    145         build_ac();
    146         Calculation();
    147         scanf("%s",str);
    148     //    cout<<str<<endl;
    149         len=strlen(str);
    150         interval();
    151     //    cout<<str<<endl;
    152         for(int i=0;i<len;i++){
    153             if(str[i]=='0')
    154             str[i]='9';
    155             else {
    156                 str[i]--;
    157                 break;
    158             }
    159         }
    160         if(str[len-1]=='0'&&len!=1) str[len-1]='';
    161         LL ans1=slove();
    162         scanf("%s",str);
    163         interval();
    164 //        memset(dp,-1,sizeof(dp));
    165         LL ans2=slove();
    166         printf("%lld
    ",((ans2-ans1)%MOD+MOD)%MOD);
    167     }
    168     return 0;
    169 }
    View Code
  • 相关阅读:
    代码
    怎么创建scrollview
    tcp/Ip http
    游戏道具
    FPS interv
    调整音乐
    插入排序
    冒泡排序
    JSON详解
    设计模式系列(2) 工厂模式之简单工厂模式
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4338329.html
Copyright © 2011-2022 走看看