zoukankan      html  css  js  c++  java
  • BZOJ 1559 JSOI2009 密码 状压dp+AC自动机+搜索

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1559

    分析:

      这个题意真的是很**啊!!!直接说每一个字符串至少出现一次不就好了吗......一开始理解错了ORZ

      观察发现这个东西是字符串相关,并且有多个模板串,所有串的长度短并且串的数量不多,最多10个,因此大概可以想到一个AC自动机上面的状压。

      首先把被包含的单词去掉,它们对决策不影响,这样在写方程的时候就可以不考虑last了。

      令f(i,l,s)表示当位于AC自动机的状态i时,已经生成了l个字符,所有单词的出现情况为s的方案数。

      f(i,l,s) = sum{ f(j,l-1,s) | j->i } + sum{ f(j,l-1,s-{i}) | j->i },s包含单词i。刷表实现即可。

      ans=sum{ f(i,L,all) | 0<=i<=np }

      当答案小于等于42的时候直接在状态转移图上面倒着搜就可以了,看那些状态对当前状态有贡献,一路搜下去,最后把所有串排个序即可。

      时间复杂度O(L*N*len*2^N),最后的方案搜索因为方案很少几乎不要时间。

      get套路之:字符串算法构造状态辅助字符串有关dp!

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 typedef long long LL;
     14 
     15 int L,N,cnt,len;
     16 char S[12][12],path[30];
     17 LL f[105][27][1050];
     18 bool vis[12];
     19 struct mstring{
     20     static const int maxn=30;
     21     char str[maxn];
     22     mstring(){ memset(str,0,sizeof(str)); }
     23     friend bool operator < (mstring a,mstring b){
     24         int n=min(strlen(a.str),strlen(b.str));
     25         for(int i=0;i<n;i++)
     26             if(a.str[i]!=b.str[i]) return a.str[i]<b.str[i];
     27         return strlen(a.str)<strlen(b.str);
     28     }
     29 }ss[50];
     30 struct Aho_Corasick_Automaton{
     31     static const int maxn=105;
     32     int np,to[maxn][26],val[maxn],fail[maxn],id[maxn];
     33     Aho_Corasick_Automaton(){
     34         np=0; memset(to[0],0,sizeof(to[0]));
     35     }
     36     void ins(char *s,int ii){
     37         int p=0,n=strlen(s);
     38         for(int i=0;i<n;i++){
     39             int w=s[i]-'a';
     40             if(!to[p][w]){
     41                 to[p][w]=++np,val[np]=id[np]=fail[np]=0;
     42                 memset(to[np],0,sizeof(to[np]));
     43             }
     44             p=to[p][w];
     45         }
     46         val[p]=1,id[p]=ii;
     47     }
     48     void getfail(){
     49         queue<int>q;
     50         fail[0]=0;
     51         for(int w=0;w<26;w++)
     52             if(to[0][w]) fail[to[0][w]]=0,q.push(to[0][w]);
     53         while(!q.empty()){
     54             int p=q.front(); q.pop();
     55             for(int w=0;w<26;w++){
     56                 int j=to[p][w];
     57                 if(!j){ to[p][w]=to[fail[p]][w]; continue; }
     58                 q.push(j);
     59                 fail[j]=to[fail[p]][w];
     60             }
     61         }
     62     }
     63 }ac;
     64 
     65 void data_in()
     66 {
     67     scanf("%d%d",&L,&N);
     68     for(int i=0;i<N;i++) scanf("%s",S[i]);
     69     for(int i=0;i<N;i++) if(!vis[i]){
     70         int n=strlen(S[i]);
     71         for(int j=0;j<N;j++) if(i!=j){
     72             int m=strlen(S[j]);
     73             if(m>n) continue;
     74             bool ok;
     75             for(int k=0;k<=n-m;k++){
     76                 ok=1;
     77                 for(int l=0;l<m;l++)
     78                     if(S[i][k+l]!=S[j][l]){ ok=0; break; }
     79                 if(ok) break;
     80             }
     81             if(ok) vis[j]=1;
     82         }
     83     }
     84     int tmp=0;
     85     for(int i=0;i<N;i++) if(!vis[i])
     86         memcpy(S[tmp++],S[i],sizeof(S[i]));
     87     N=tmp;
     88 }
     89 void run(int i,int l,int s)
     90 {
     91     if(i==0&&l==0&&s==0){
     92         cnt++;
     93         for(int j=len-1;j>=0;j--)
     94             ss[cnt].str[len-1-j]=path[j];
     95         ss[cnt].str[len]='';
     96         return;
     97     }
     98     for(int j=0;j<=ac.np;j++) if(f[j][l-1][s])
     99     for(int w=0;w<26;w++) if(ac.to[j][w]==i){
    100         path[len++]=w+'a'; run(j,l-1,s);
    101         len--; break;
    102     }
    103     if(ac.val[i]){
    104         s^=1<<ac.id[i];
    105         for(int j=0;j<=ac.np;j++) if(f[j][l-1][s])
    106         for(int w=0;w<26;w++) if(ac.to[j][w]==i){
    107             path[len++]=w+'a'; run(j,l-1,s);
    108             len--; break;
    109         }
    110     }
    111 }
    112 void work()
    113 {
    114     for(int i=0;i<N;i++) ac.ins(S[i],i);
    115     ac.getfail();
    116     f[0][0][0]=1;
    117     int all=(1<<N)-1;
    118     for(int l=0;l<L;l++)
    119     for(int i=0;i<=ac.np;i++){
    120         int ori=ac.val[i]?1<<ac.id[i]:0;
    121         for(int s=ori;s<=all;s=(s+1)|ori){
    122             if(!f[i][l][s]) continue;
    123             for(int w=0;w<26;w++){
    124                 int j=ac.to[i][w];
    125                 if(ac.val[j]) f[j][l+1][s|(1<<ac.id[j])]+=f[i][l][s];
    126                 else f[j][l+1][s]+=f[i][l][s];
    127             }
    128         }
    129     }
    130     LL ans=0;
    131     for(int i=0;i<=ac.np;i++) ans+=f[i][L][all];
    132     cout<<ans<<'
    ';
    133     if(ans<=42){
    134         for(int i=0;i<=ac.np;i++)
    135             if(f[i][L][all]) run(i,L,all);
    136         sort(ss+1,ss+ans+1);
    137         for(int i=1;i<=ans;i++) puts(ss[i].str);
    138     }
    139 }
    140 int main()
    141 {
    142     data_in();
    143     work();
    144     return 0;
    145 }
    View Code
  • 相关阅读:
    语音合成
    JAVA的18条BASE
    Java关键字final、static使用总结
    JAVA学习之路:不走弯路,就是捷径
    每个java初学者都应该搞懂的问题
    Tomcat5.5.9+JSP经典配置实例
    FineUI控件集合
    AngularJS基础
    数据库优化方案之SQL脚本优化
    数据库分库分表策略之MS-SQL读写分离方案
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8746860.html
Copyright © 2011-2022 走看看