HDU4057 Rescue the Rabbit(AC自动机+状压DP)
题目大概是给几个DNA片段以及它们各自的权值,如果一个DNA包含某个片段那么它的价值就加上这个片段的权值,同时包含多个相同DNA片段也只加一次,问长度l的DNA可能的最大价值。
与HDU2825大同小异。
- dp[i][j][S]表示长度i(自动机转移i步)、后缀状态为自动机第j个结点、包含的DNA片段为集合S 的DNA最大价值
- dp[0][0][0]=0
- 我为人人转移,从dp[i][j][S]向ATCG四个方向更新dp[i+1][j'][S']
- 注意的是要用滚动数组,不然要开上百兆数组。
- 用滚动数组要注意初始化。
- 转移过程有些计算可以预处理出来,存在数组里,虽然不预处理应该也不会TLE,题目时间给了10000ms。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 #define INF (1<<30) 6 int tn,ch[1111][4],fail[1111],flag[1111]; 7 int idx[128]; 8 void insert(char *s,int k){ 9 int x=0; 10 for(int i=0; s[i]; ++i){ 11 int y=idx[s[i]]; 12 if(ch[x][y]==0) ch[x][y]=++tn; 13 x=ch[x][y]; 14 } 15 flag[x]|=1<<k; 16 } 17 void init(){ 18 memset(fail,0,sizeof(fail)); 19 queue<int> que; 20 for(int i=0; i<4; ++i){ 21 if(ch[0][i]) que.push(ch[0][i]); 22 } 23 while(!que.empty()){ 24 int x=que.front(); que.pop(); 25 for(int i=0; i<4; ++i){ 26 if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i],flag[ch[x][i]]|=flag[ch[fail[x]][i]]; 27 else ch[x][i]=ch[fail[x]][i]; 28 } 29 } 30 } 31 int d[2][1111][1<<10],VAL[1<<10]; 32 int main(){ 33 idx['A']=0; idx['G']=1; idx['T']=2; idx['C']=3; 34 int m,n,a; 35 char str[111]; 36 int val[11]; 37 while(~scanf("%d%d",&m,&n)){ 38 tn=0; 39 memset(ch,0,sizeof(ch)); 40 memset(flag,0,sizeof(flag)); 41 for(int i=0; i<m; ++i){ 42 scanf("%s%d",str,val+i); 43 if(strlen(str)>100) continue; 44 insert(str,i); 45 } 46 for(int i=1; i<(1<<m); ++i){ 47 for(int j=0; j<m; ++j){ 48 if((i>>j)&1) VAL[i]=VAL[i^(1<<j)]+val[j]; 49 } 50 } 51 init(); 52 for(int j=0; j<=tn; ++j){ 53 for(int k=0; k<(1<<m); ++k) d[0][j][k]=-INF; 54 } 55 d[0][0][0]=0; 56 for(int i=0; i<n; ++i){ 57 int x=i&1; 58 for(int j=0; j<=tn; ++j){ 59 for(int k=0; k<(1<<m); ++k) d[x^1][j][k]=-INF; 60 } 61 for(int j=0; j<=tn; ++j){ 62 for(int k=0; k<(1<<m); ++k){ 63 if(d[x][j][k]==-INF) continue; 64 for(int y=0; y<4; ++y){ 65 d[x^1][ch[j][y]][k|flag[ch[j][y]]]=max(d[x^1][ch[j][y]][k|flag[ch[j][y]]],d[x][j][k]+VAL[k^(k|flag[ch[j][y]])]); 66 } 67 } 68 } 69 } 70 int res=-INF; 71 for(int i=0; i<=tn; ++i){ 72 for(int j=0; j<(1<<m); ++j) res=max(res,d[n&1][i][j]); 73 } 74 if(res<0) puts("No Rabbit after 2012!"); 75 else printf("%d\n",res); 76 } 77 return 0; 78 }