UVALive 4126 (ac自动机做状态类)

来源:互联网 发布:用linux可以上百度吗 编辑:程序博客网 时间:2024/04/29 14:58

题意:

给定最多10个长度不超过10的子串,让构造长度为n(n<=25)的字符串使得给定的子串都在该串中出现,问这种串有多少。

分析:

暴力是26^25中可能性,那么怎样精简状态,可以定义d[ i ][ j ][ s ]为当前构造的串长为i且已经到达自动机j位置,已经生成的子串状态为s,接着往下构造所能生成的合法串有多少。

状态转移,就是直接暴力枚举一下下一个字母是谁,在自动机中做状态转移。

一开始用ac自动机做状态不是很好理解,j其实是代表着前面走到i位置,所有最大匹配在自动机中为j的串,那么转移也如此。

#include <cstdio>#include <algorithm>#include <cstring>#include <iostream>#include <queue>#include <set>#include <string>using namespace std;typedef long long ll;#define rep(i,n) for(int i=0;i<(int)n;i++)#define rep1(i,x,y) for(int i=x;i<=y;i++)const int maxnnode = 110;const int sigma_size = 26;struct Trie{  int ch[maxnnode][sigma_size];  int val[maxnnode],f[maxnnode],last[maxnnode];  int cnt;  void init(){     cnt = 0; memset(ch[0],0,sizeof(ch[0]));     val[0] = 0;     memset(val,0,sizeof(val));  }  int id(char c){return c-'a';}  void insert(char* s,int x){     int n=strlen(s),u=0;     rep(i,n){        int c = id(s[i]);        if(!ch[u][c]){            ch[u][c]=++cnt;            val[cnt]=0;            memset(ch[cnt],0,sizeof(ch[cnt]));        }        u = ch[u][c];     }     val[u] = x;  }  void build(){      f[0] = last[0]=0;      queue<int> Q;      rep(i,sigma_size){          if(ch[0][i]) Q.push(ch[0][i]),f[ch[0][i]]=last[ch[0][i]]=0;      }      while(!Q.empty()){          int u=Q.front(); Q.pop();          rep(i,sigma_size){               if(!ch[u][i]){                   ch[u][i] = ch[f[u]][i];                   continue;               }               int v = ch[u][i];               f[v] = ch[f[u]][i];               last[v] = (val[f[v]] ? f[v] : last[f[v]]);               Q.push(v);          }      }  }  int print_(int u){      cnt = 0;      while(u) {          cnt|=(1<<(val[u]-1));          u = last[u];      }      return cnt;  }}ac;const int maxn = 26;ll d[maxn][maxnnode][(1<<10)+10];int n,m;ll dp(){   memset(d[n],0,sizeof(d[n]));   for(int j=0;j<maxnnode;j++) d[n][j][(1<<m)-1]=1;   int te = ac.cnt;   for(int i=n-1;i>=0;i--)      rep1(j,0,te)        for(int s=0;s<(1<<m);s++){          d[i][j][s] = 0;          rep(k,sigma_size){            int c = ac.ch[j][k];            int ts = ac.print_(ac.val[c] ? c : ac.last[c]);            d[i][j][s]+=d[i+1][c][(s|ts)];          }   }   return d[0][0][0];}vector<char> aa;void print_(int i,int j,int s){   if(i == n){       rep(i,aa.size()) cout<<aa[i]; cout<<endl;       return ;   }   rep(k,sigma_size){       int c = ac.ch[j][k];       int ts = ac.print_(ac.val[c] ? c : ac.last[c]);       if(d[i+1][c][s|ts]) {           aa.push_back('a'+k);           print_(i+1,c,s|ts);           aa.pop_back();       }   }}set<string> vvis;int main(){   int kase=1;   vvis.clear();   while(scanf("%d %d",&n,&m)==2 && n){       vvis.clear();       ac.init();       int rm = 0;       rep(i,m){          char s[30];          scanf("%s",s);          string te = s ;          if(!vvis.count(te)){             ac.insert(s,++rm);             vvis.insert(te);          }       }       m = rm;       ac.build();       ll ans = dp();       aa.clear();       printf("Case %d: %lld suspects\n",kase++,ans);       if(ans <= 42){           print_(0,0,0);       }   }   return 0;}


0 0
原创粉丝点击