【HDU3341】 Lost's revenge (AC自动机+状压DP)

Lost's revenge
Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u

Description

Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is the man called "nuclear weapon of FZU,descendant of Jingrun", because of his talent in the field of number theory. So Lost had never won the game. He was so ashamed and angry, but he didn't know how to improve his level of number theory. 

One noon, when Lost was lying on the bed, the Spring Brother poster on the wall(Lost is a believer of Spring Brother) said hello to him! Spring Brother said, "I'm Spring Brother, and I saw AekdyCoin shames you again and again. I can't bear my believers were being bullied. Now, I give you a chance to rearrange your gene sequences to defeat AekdyCoin!". 

It's soooo crazy and unbelievable to rearrange the gene sequences, but Lost has no choice. He knows some genes called "number theory gene" will affect one "level of number theory". And two of the same kind of gene in different position in the gene sequences will affect two "level of number theory", even though they overlap each other. There is nothing but revenge in his mind. So he needs you help to calculate the most "level of number theory" after rearrangement.

Input

There are less than 30 testcases. 
For each testcase, first line is number of "number theory gene" N(1<=N<=50). N=0 denotes the end of the input file. 
Next N lines means the "number theory gene", and the length of every "number theory gene" is no more than 10. 
The last line is Lost's gene sequences, its length is also less or equal 40. 
All genes and gene sequences are only contains capital letter ACGT. 

Output

For each testcase, output the case number(start with 1) and the most "level of number theory" with format like the sample output.

Sample Input

3
AC
CG
GT
CGAT
1
AA
AAA
0

Sample Output

Case 1: 3 Case 2: 2
 
 
【题意】
  给定一些需要匹配的串,然后在给定一个目标串,现在可以通过交换目标串中任意两个位置的字符,要求最后生成的串匹配尽量多的匹配串,可以重复匹配。有重复的串的。
 
【分析】
  这题限定了每个字母选取的个数,上限为40。
  如果简单的表示状态的话,有41*41*41*41种情况,再加上DP的一维记录现在走到的节点的位置的话,就会爆空间。
  但我们会发现——其实很多都是没有用的,同时满足四个上限的话,很多情况都取不到,最多也就11*11*11*11种情况而已。
  但是每个字母的上限还是有40啊?怎么办呢? 就要用到k进制把状态压成一个十进制数。(k根据题目数据而定)
  k进制——类比10进制就能Y出来了。
  所以状态是14641种。
  然后DP,
  我的DP是,最外层for一共填了多少个字母,那么就可以保证DP大状态时小状态已经求出来了。(不会告诉你就这个我就纠结了很久啊QAQ)
  后面几个FOR都是枚举各个字母的选取(有点丑,但是觉得这样好打)
 
代码如下:
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 510
  9 #define Maxl 15000
 10 #define INF 0xfffffff
 11 #define Mod 20090717
 12 
 13 int n;
 14 char s[210];
 15 int v[5],k[5],ln;
 16 
 17 struct node
 18 {
 19     // int cnt;
 20     int fail,mark;
 21     int son[5];
 22 }t[Maxn];int tot;
 23 int num;
 24 int p[210];
 25 
 26 void upd(int x)
 27 {
 28     // t[x].cnt=0;
 29     t[x].mark=0;
 30     memset(t[x].son,0,sizeof(t[x].son));
 31 }
 32 
 33 int mymin(int x,int y) {return x<y?x:y;}
 34 int mymax(int x,int y) {return x>y?x:y;}
 35 
 36 void read_trie()
 37 {
 38     scanf("%s",s+1);
 39     int len=strlen(s+1);
 40     int now=0;
 41     for(int i=1;i<=len;i++)
 42     {
 43         if(s[i]=='C') s[i]='B';
 44         else if(s[i]=='G') s[i]='C';
 45         else if(s[i]=='T') s[i]='D';
 46         int ind=s[i]-'A'+1;
 47         if(!t[now].son[ind]) 
 48         {
 49             t[now].son[ind]=++tot;
 50             upd(tot);
 51         }
 52         now=t[now].son[ind];
 53         if(i==len) t[now].mark++;
 54     }
 55 }
 56 
 57 queue<int > q;
 58 void build_AC()
 59 {
 60     while(!q.empty()) q.pop();
 61     q.push(0);
 62     while(!q.empty())
 63     {
 64         int x=q.front();q.pop();
 65         for(int i=1;i<=4;i++) 
 66         {
 67             if(t[x].son[i])
 68             {
 69                 t[t[x].son[i]].fail=x?t[t[x].fail].son[i]:0;
 70                 q.push(t[x].son[i]);
 71             }
 72             else t[x].son[i]=t[t[x].fail].son[i];
 73         }
 74         t[x].mark+=t[t[x].fail].mark;
 75     }
 76 }
 77 
 78 int f[Maxn][Maxl];
 79 int a[5];
 80 void dp()
 81 {
 82     memset(f,-1,sizeof(f));
 83     f[0][0]=0;
 84     int ans=0;
 85      for(int l=0;l<=ln;l++) //选取的字母个数
 86     for(int i=0;i<=tot;i++) //走到节点i
 87       for(a[1]=mymax(l-v[4]-v[3]-v[2],0);a[1]<=mymin(v[1],l);a[1]++)//if(f[i-1][j][l]!=0)
 88        for(a[2]=mymax(l-v[4]-v[3]-a[1],0);a[2]<=mymin(v[2],l);a[2]++)
 89         for(a[3]=mymax(l-v[4]-a[1]-a[2],0);a[3]<=mymin(v[3],l);a[3]++)
 90         {
 91             a[4]=l-a[1]-a[2]-a[3];
 92             int now=a[1]*k[1]+a[2]*k[2]+a[3]*k[3]+a[4];
 93             if(f[i][now]==-1) continue; 
 94             for(int j=1;j<=4;j++) if(a[j]+1<=v[j])
 95             {
 96                 // if(t[t[i].son[j]].mark) 
 97                  f[t[i].son[j]][now+k[j]]=mymax(f[t[i].son[j]][now+k[j]],f[i][now]+t[t[i].son[j]].mark);
 98                 // else f[t[i].son[j]][now+k[j]]=mymax(f[t[i].son[j]][now+k[j]],f[i][now]);
 99                 ans=mymax(ans,f[t[i].son[j]][now+k[j]]);
100             }
101         }
102     printf("%d\n",ans);
103 }
104 
105 char ss[50];
106 void init()
107 {
108     tot=0;
109     upd(0);
110     for(int i=1;i<=n;i++)
111     {
112         read_trie();
113     }
114     build_AC();
115     scanf("%s",ss+1);
116     ln=strlen(ss+1);
117     v[1]=v[2]=v[3]=v[4]=0;
118     for(int i=1;i<=ln;i++)
119     {
120         if(ss[i]=='C') ss[i]='B';
121         else if(ss[i]=='G') ss[i]='C';
122         else if(ss[i]=='T') ss[i]='D';
123         v[ss[i]-'A'+1]++;
124     }
125     int maxx=(v[1]+1)*(v[2]+1)*(v[3]+1)*(v[4]+1);
126     k[1]=(v[2]+1)*(v[3]+1)*(v[4]+1);
127     k[2]=(v[3]+1)*(v[4]+1);
128     k[3]=(v[4]+1);k[4]=1;
129 }
130 
131 int main()
132 {
133     int kase=0;
134     while(1)
135     {
136         scanf("%d",&n);
137         if(n==0) break;
138         init();
139         printf("Case %d: ",++kase);
140         dp();
141     }
142     return 0;
143 }
[HDU3341]

 

2016-07-12 09:42:49

posted @ 2016-07-12 09:39  konjak魔芋  阅读(644)  评论(0编辑  收藏  举报