BZOJ5337 [TJOI2018] 碱基序列 【哈希】【动态规划】

题目分析:

这道题的难点在于要取模,而题面没有写。

容易想到一个O(1E7)的dp。KMP或者哈希得到相关位置然后对于相关位置判断上一个位置有多少种情况。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 10200;
 5 
 6 const int mod = 1000000007;
 7 
 8 int n;
 9 string str;
10 string fm[102][12];
11 int num[102];
12 
13 const int Kh = 2;
14 
15 struct hnum{
16     int base;
17     unsigned long long multi[10200];
18     unsigned long long hash[10200];
19 }h[2];
20 
21 void read(){
22     ios::sync_with_stdio(false);
23     cin.tie();
24     cin >> n;
25     cin >> str;
26     for(int i=1;i<=n;i++){
27     cin >> num[i];
28     for(int j=1;j<=num[i];j++) {cin >> fm[i][j];}
29     }
30 }
31 
32 long long rm[2][maxn];
33 int d[maxn];
34 
35 void KMP(int c,int m){
36     memset(d,0,sizeof(d));
37     string &p = fm[c][m];
38     for(int o = 0;o<Kh;o++){
39     unsigned long long now = 0;
40     for(int i=0;i<p.length();i++)
41         now += (p[i]-'A'+1)*h[o].multi[i];
42     for(int i=p.length()-1;i<str.length();i++){
43         unsigned long long data;
44         if(i!=p.length()-1)data = h[o].hash[i]-h[o].hash[i-p.length()];
45         else data = h[o].hash[i];
46         if(now == data) d[i]++;
47         now = now*h[o].base;
48     }
49     }
50     for(int i=0;i<str.length();i++) if(d[i]==Kh)d[i]=1;else d[i]=0;
51 }
52 
53 void build_hash(){
54     for(int i=0;i<Kh;i++){
55     h[i].multi[0] = 1;
56     for(int j=1;j<str.length();j++){
57         h[i].multi[j] = h[i].multi[j-1]*h[i].base;
58     }
59     h[i].hash[0] = str[0]-'A'+1;
60     for(int j=1;j<str.length();j++){
61         h[i].hash[j] = h[i].hash[j-1]+(str[j]-'A'+1)*h[i].multi[j];
62     }
63     }
64 }
65 
66 void work(){
67     h[0].base = 19,h[1].base = 31;
68     build_hash();
69     for(int i=1;i<=num[1];i++){
70     KMP(1,i); for(int k=0;k<str.length();k++) rm[1][k] += d[k];
71     }
72     for(int i=2;i<=n;i++){
73     memset(rm[i&1],0,sizeof(rm[i&1]));
74     for(int j=1;j<=num[i];j++){
75         KMP(i,j); int len = fm[i][j].length();
76         for(int k=0;k<str.length();k++){
77         if(d[k]){
78             if(k-len<0) continue;
79             rm[i&1][k] += rm[(i+1)&1][k-len];
80             rm[i&1][k] %= mod;
81         }
82         }
83     }
84     }
85     long long ans = 0;
86     for(int j=0;j<str.length();j++){
87     ans += rm[n&1][j]; ans %= mod;
88     }
89     printf("%lld",ans);
90 }
91 
92 int main(){
93     read();
94     work();
95     return 0;
96 }

 

posted @ 2018-05-19 17:10  menhera  阅读(413)  评论(0编辑  收藏  举报