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
  • 相关阅读:
    hadoop再次集群搭建(3)-如何选择相应的hadoop版本
    48. Rotate Image
    352. Data Stream as Disjoint Interval
    163. Missing Ranges
    228. Summary Ranges
    147. Insertion Sort List
    324. Wiggle Sort II
    215. Kth Largest Element in an Array
    快速排序
    280. Wiggle Sort
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4338329.html
Copyright © 2011-2022 走看看