poj

链接:https://vjudge.net/problem/POJ-1625
思路:跟北京站dp一样,不过就是坑很多就是了,首先读进来的字符可能是负数,需要映射一下变成正的,第二就是dp要用大整数,我以为他没说取模答案就一定在范围内,结果后来想了下很容易就要爆long long啊,结果果然还要大数,就在网上找了一个看起来比较简单和漂亮的模板。再说说这个题,就是自动机上dp的题,原来用矩阵加速,这个题因为比较小就不用加速了,直接dp就好,最后直接把所有节点的值加起来就是答案,实在不会看之前北京站的那个dp,那个是取模的就简单多了。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

#include <cstring>
#include <queue>

using namespace std;

const int maxnode = 120;
const int sigma_size = 300;

int n, m, p;
char s[15][15];
char str[60];
int id[300];

int ch[maxnode][sigma_size];
int val[maxnode];
int f[maxnode];
int last[maxnode];
int sz;

struct {
int A[25];
enum {
MOD = 10000
};

BigInteger() {
memset(A, 0, sizeof(A));
A[0] = 1;
}

void set(int x) {
memset(A, 0, sizeof(A));
A[0] = 1;
A[1] = x;
}

void print() {
printf("%d", A[A[0]]);
for (int i = A[0] - 1; i > 0; i--) {
if (A[i] == 0) {
printf("0000");
continue;
}
for (int k = 10; k * A[i] < MOD; k *= 10) printf("0");
printf("%d", A[i]);
}
printf("n");
}

int &operator[](int p) { return A[p]; }

const int &operator[](int p) const { return A[p]; }

BigInteger operator+(const BigInteger &B) {
BigInteger C;
C[0] = max(A[0], B[0]);
for (int i = 1; i <= C[0]; i++)
C[i] += A[i] + B[i], C[i + 1] += C[i] / MOD, C[i] %= MOD;
if (C[C[0] + 1] > 0) C[0]++;
return C;
}

BigInteger operator*(const BigInteger &B) {
BigInteger C;
C[0] = A[0] + B[0];
for (int i = 1; i <= A[0]; i++)
for (int j = 1; j <= B[0]; j++) {
C[i + j - 1] += A[i] * B[j], C[i + j] += C[i + j - 1] / MOD, C[i + j - 1] %= MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
}dp[maxnode][100];

void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}

int idx(char c) {
return id[c + 100];
}

void insert(char *s,int v = 1) {
int n = strlen(s);
int u = 0;
for (int i = 0; i < n; i++) {
int c = idx(s[i]);
if (!ch[u][c]) {
ch[u][c] = sz;
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz++] = 0;
}
u = ch[u][c];
}
val[u] = v;
}

void getfail() {
queue<int> q;
f[0] = 0;
for (int i = 0; i < sigma_size; i++) {
int u = ch[0][i];
if (u) {
f[u] = last[u] = 0;
q.push(u);
}
}
while (!q.empty()) {
int r = q.front();
q.pop();
val[r] |= val[f[r]];
for (int c = 0; c < sigma_size; c++) {
int u = ch[r][c];
if (!u) {
ch[r][c] = ch[f[r]][c];
continue;
}
q.push(u);
int v = f[r];
while (v && !ch[v][c])v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}


int main(){
while(~scanf("%d %d %d", &n, &m, &p)) {
scanf("%s", str);
memset(id, 0, sizeof(id));
for (int i = 0; i < n; i++) id[str[i] + 100] = i;
init();
for (int i = 0; i < p; i++) {
scanf("%s", s[i]);
insert(s[i]);
}
getfail();
for(int i = 0; i <= m; i++){
for(int j = 0; j < sz; j++){
dp[j][i].set(0);
}
}
dp[0][0].set(1);
for (int i = 0; i < m; i++) {
for (int j = 0; j < sz; j++) {
if (val[j])continue;
for (int k = 0; k < n; k++) {
if (!val[ch[j][k]])dp[ch[j][k]][i + 1] = dp[ch[j][k]][i + 1] + dp[j][i];
}
}
}
BigInteger r;
r.set(0);
for (int i = 0; i < sz; i++) {
if (!val[i])
r = r + dp[i][m];
}
r.print();
}
return 0;
}