[HDOJ6494] 球赛(DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6494

中文题面。

先得11分的为赢,则10平后,先多得2分的赢。那么遇到这两种情况后面的场次都是随意的。于是就可以设计状态了:f(i,j,k)表示前i场A赢j局,B赢k局时的方案数。

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
// ⣿⣿⣿⣿⣿⣿⢟⣡⣴⣶⣶⣦⣌⡛⠟⣋⣩⣬⣭⣭⡛⢿⣿⣿⣿⣿
// ⣿⣿⣿⣿⠋⢰⣿⣿⠿⣛⣛⣙⣛⠻⢆⢻⣿⠿⠿⠿⣿⡄⠻⣿⣿⣿ 
// ⣿⣿⣿⠃⢠⣿⣿⣶⣿⣿⡿⠿⢟⣛⣒⠐⠲⣶⡶⠿⠶⠶⠦⠄⠙⢿ 
// ⣿⠋⣠⠄⣿⣿⣿⠟⡛⢅⣠⡵⡐⠲⣶⣶⣥⡠⣤⣵⠆⠄⠰⣦⣤⡀ 
// ⠇⣰⣿⣼⣿⣿⣧⣤⡸⢿⣿⡀⠂⠁⣸⣿⣿⣿⣿⣇⠄⠈⢀⣿⣿⠿ 
// ⣰⣿⣿⣿⣿⣿⣿⣿⣷⣤⣈⣙⠶⢾⠭⢉⣁⣴⢯⣭⣵⣶⠾⠓⢀⣴
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣉⣤⣴⣾⣿⣿⣦⣄⣤⣤⣄⠄⢿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠈⢿
// ⣿⣿⣿⣿⣿⣿⡟⣰⣞⣛⡒⢒⠤⠦⢬⣉⣉⣉⣉⣉⣉⣉⡥⠴⠂⢸
// ⠻⣿⣿⣿⣿⣏⠻⢌⣉⣉⣩⣉⡛⣛⠒⠶⠶⠶⠶⠶⠶⠶⠶⠂⣸⣿
// ⣥⣈⠙⡻⠿⠿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⠿⠛⢉⣠⣶⣶⣿⣿
// ⣿⣿⣿⣶⣬⣅⣒⣒⡂⠈⠭⠭⠭⠭⠭⢉⣁⣄⡀⢾⣿⣿⣿⣿⣿⣿

#include <bits/stdc++.h>
using namespace std;

using LL = long long;
const int maxn = 10100;
LL f[2][12][12];
char s[maxn];
int n;

pair<int, int> Next(int x, int y, int flag) {
if (flag == 0) {
x++;
} else {
y++;
}
if (x >= 10 && y >= 10) {
if (abs(x - y) > 1) {
return {0, 0};
}
if (x == y) {
return {10, 10};
}
if (x > y) {
return {11, 10};
}
if (x < y) {
return {10, 11};
}
}
if (x > 10 || y > 10) {
return {0, 0};
}
return {x, y};
}

signed main() {
// freopen("in", "r", stdin);
int T, x, y;
scanf("%d", &T);
while (T--) {
scanf("%s", s);
n = strlen(s);
memset(f, -1, sizeof f);
f[0][0][0] = 0;
for (int i = 0; i < n; i++) {
int l = !(i & 1);
for (int j = 0; j <= 11; j++) {
for (int k = 0; k <= 11; k++) {
f[l][j][k] = -1;
}
}
for (int j = 0; j <= 11; j++) {
for (int k = 0; k <= 11; k++) {
if (f[!l][j][k] == -1) {
continue;
}
if (s[i] != 'B') {
tie(x, y) = Next(j, k, 0);
f[l][x][y] = max(f[l][x][y], f[!l][j][k] + (x + y == 0));
}
if (s[i] != 'A') {
tie(x, y) = Next(j, k, 1);
f[l][x][y] = max(f[l][x][y], f[!l][j][k] + (x + y == 0));
}
}
}
}
LL ret = 0;
for (int i = 0; i <= 11; i++) {
for (int j = 0; j <= 11; j++) {
ret = max(ret, f[n & 1][i][j]);
}
}
printf("%lld\n", ret);
}
return 0;
}