Solution S o l u t i o n
先考虑已知模板串的情况。
如果出现ABB
这样A
的个数比B
的个数少的,那么A
是不可能会向左走的。
整个模板串就会因为这个分隔开成若干个独立游戏。
我们要计算每个游戏的值的和。
维护两个变量
ans
a
n
s
和
cur
c
u
r
分别表示A
能比B
多走
ans
a
n
s
步,当前游戏A
的个数比B
的个数多几个。
显然的有以下三个转移:
-
patterni=
p
a
t
t
e
r
n
i
=
A
, cur=max(cur+1,0) c u r = m a x ( c u r + 1 , 0 ) 。 -
patterni=
p
a
t
t
e
r
n
i
=
B
, cur=min(cur−1,0) c u r = m i n ( c u r − 1 , 0 ) 。 -
patterni=
p
a
t
t
e
r
n
i
=
.
, ans=ans+cur a n s = a n s + c u r 。
求方案数就很简单了
dpi,ans,cur
d
p
i
,
a
n
s
,
c
u
r
把所有状态记下来就好了。
数组开小sb了qwq
// BEGIN CUT HERE
// END CUT HERE
#line 5 "GameOfTokens.cpp"
#include <bits/stdc++.h>
using namespace std;
const int N = 52;
const int M = 5050;
const int MOD = 1000000007;
int dp[N][M][2 * N];
char p[N];
int n, m;
class GameOfTokens {
public:
inline void Add(int &x, int a) {
x = (x + a) % MOD;
}
inline int &f(int i, int j, int k) {
return dp[i][j + 2501][k + 51];
}
int count(string pattern) {
memset(dp, 0, sizeof dp);
n = pattern.size(); m = n * n;
for (int i = 1; i <= n; i++)
p[i] = pattern[i - 1];
if (p[n] == 'A' || p[n] == '?') f(n, 0, 1) = 1;
if (p[n] == 'B' || p[n] == '?') f(n, 0, -1) = 1;
if (p[n] == '.' || p[n] == '?') f(n, 0, 0) = 1;
for (int i = n - 1; ~i; i--) {
for (int j = -m; j <= m; j++)
for (int k = -n; k <= n; k++) {
int res = f(i + 1, j, k);
if (!res) continue;
if (p[i] == 'A' || p[i] == '?') {
int ans = j;
int cur = max(k + 1, 0);
Add(f(i, ans, cur), res);
}
if (p[i] == 'B' || p[i] == '?') {
int ans = j;
int cur = min(k - 1, 0);
Add(f(i, ans, cur), res);
}
if (p[i] == '.' || p[i] == '?') {
int cur = k;
int ans = j + cur;
Add(f(i, ans, cur), res);
}
}
}
int ans = 0;
for (int j = 1; j <= m; j++)
for (int k = -n; k <= n; k++)
Add(ans, f(1, j, k));
return ans;
}
// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { string Arg0 = ".AB"; int Arg1 = 0; verify_case(0, Arg1, count(Arg0)); }
void test_case_1() { string Arg0 = "???B"; int Arg1 = 1; verify_case(1, Arg1, count(Arg0)); }
void test_case_2() { string Arg0 = "???????...BBB"; int Arg1 = 0; verify_case(2, Arg1, count(Arg0)); }
void test_case_3() { string Arg0 = "?.A?.B??.??B?"; int Arg1 = 517; verify_case(3, Arg1, count(Arg0)); }
void test_case_4() { string Arg0 = "????????????????????"; int Arg1 = 612621096; verify_case(4, Arg1, count(Arg0)); }
// END CUT HERE
};
// BEGIN CUT HERE
int main(void) {
GameOfTokens ___test;
___test.run_test(-1);
system("pause");
}
// END CUT HERE