hdu3341Lost's revenge(ac自动机+dp)
类似的dp省赛时就做过了,不过这题卡内存,需要把当前状态hash一下,可以按进制来算出当前的状态,因为所有的状态数是不会超过10*10*10*10的,所以完全可以把这些存下来。
刚开始把trie的的遍历节点写在外层循环了,一直WA,后来想了一下,状态是只会向前走的,但是节点不一样,如果由 当前节点的状态-》下一节点的状态,下一节点有可能是在当前节点之前的,这样是不对的,所以需要由当前状态的节点 -》下一状态的节点 。
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 using namespace std; 11 #define N 510 12 #define LL long long 13 #define INF -1 14 const double eps = 1e-8; 15 const double pi = acos(-1.0); 16 const double inf = ~0u>>2; 17 const int child_num = 4; 18 char vir[22],s[105]; 19 int mp[3200010]; 20 class AC 21 { 22 private: 23 int ch[N][child_num]; 24 int Q[N]; 25 int fail[N]; 26 int val[N]; 27 int id[127]; 28 int sz; 29 int dp[N][20000]; 30 public: 31 void init() 32 { 33 fail[0] = 0; 34 id['A'] = 0,id['G'] = 1,id['T'] = 2,id['C'] = 3; 35 } 36 void reset() 37 { 38 memset(ch[0],0,sizeof(ch[0])); 39 memset(val,0,sizeof(val)); 40 sz = 1; 41 } 42 void insert(char *a,int key) 43 { 44 int p =0 ; 45 for( ; *a ; a++) 46 { 47 int d = id[*a]; 48 if(ch[p][d]==0) 49 { 50 memset(ch[sz],0,sizeof(ch[sz])); 51 ch[p][d] = sz++; 52 } 53 p = ch[p][d]; 54 } 55 val[p] += key; 56 } 57 void construct() 58 { 59 int i,head=0,tail = 0; 60 for(i = 0;i < child_num ; i++) 61 { 62 if(ch[0][i]) 63 { 64 fail[ch[0][i]] = 0; 65 Q[tail++] = ch[0][i]; 66 } 67 } 68 while(head!=tail) 69 { 70 int u = Q[head++]; 71 val[u]+=val[fail[u]]; 72 for(i =0 ; i < child_num ; i++) 73 { 74 if(ch[u][i]) 75 { 76 fail[ch[u][i]] = ch[fail[u]][i]; 77 Q[tail++] = ch[u][i]; 78 } 79 else ch[u][i] = ch[fail[u]][i]; 80 } 81 } 82 } 83 void work(char *s,int kk) 84 { 85 int k = strlen(s); 86 int num[5]= {0},pp[5]; 87 memset(num,0,sizeof(num)); 88 int o = 0 ,i,j,g,e,z,y; 89 for(i = 0 ; i < k ;i++) 90 { 91 num[id[s[i]]]++; 92 } 93 pp[0] = 1; 94 for(i = 1; i <= 4 ; i++) 95 pp[i] = pp[i-1]*42; 96 memset(mp,-1,sizeof(mp)); 97 for(i = 0 ; i <= num[0] ; i++) 98 for(j = 0;j <= num[1] ; j++) 99 for(g =0 ; g <= num[2] ; g++) 100 for(e = 0 ; e <= num[3] ;e++) 101 { 102 int sum = e*pp[3]+g*pp[2]+j*42+i; 103 o++; 104 mp[sum] = o; 105 } 106 memset(dp,-1,sizeof(dp)); 107 dp[0][1] = 0; 108 for(i = 0 ; i <= num[0] ; i++) 109 for(j = 0;j <= num[1] ; j++) 110 for(g = 0 ; g <= num[2] ; g++) 111 for(e = 0 ; e <= num[3] ;e++) 112 { 113 for(z = 0 ;z < sz ; z++) 114 { 115 int sum = e*pp[3]+g*pp[2]+j*42+i; 116 if(dp[z][mp[sum]]==-1) continue; 117 for(y = 0; y < child_num ; y++) 118 { 119 int yy = ch[z][y]; 120 int ss = pp[y]+sum; 121 if(mp[ss]==-1) continue; 122 dp[yy][mp[ss]] = max(dp[yy][mp[ss]],dp[z][mp[sum]]+val[yy]); 123 } 124 } 125 } 126 int ans = 0; 127 for(i = 0;i < sz ; i++) 128 { 129 ans=max(dp[i][o],ans); 130 } 131 printf("Case %d: ",kk); 132 printf("%d\n",ans); 133 } 134 }ac; 135 int main() 136 { 137 int n,kk=0; 138 ac.init(); 139 while(scanf("%d",&n)&&n) 140 { 141 ac.reset(); 142 kk++; 143 while(n--) 144 { 145 scanf("%s",vir); 146 ac.insert(vir,1); 147 } 148 ac.construct(); 149 scanf("%s",s); 150 ac.work(s,kk); 151 } 152 return 0; 153 }