题解:P14256 平局(draw)
容易想到大概率需要从左往右扫描,然后用一些 dp of dp 或者贪心 of dp 之类的做。
感受一下,这里大概率应该是贪心 of dp。下面记
先把所有相邻相同的字母消除掉,然后发现我们其实是不断这样操作:选择两个相同的字母
首先我们观察:若存在形如
剩下的只需要考虑
如果不存在形如
-
如果当前串为形如
\mathtt {\dots ACBACBAC} ,加入一个\mathtt B 后,直接令j 加一;加入一个\mathtt C 后,j 不变,直接令答案加上对应贡献;加入一个\mathtt A 后,显然可以将\mathtt {ACA} 合并成一个\mathtt A 并将答案加上对应贡献。 -
如果当前串为形如
\mathtt {\dots ABCABCAB} ,加入一个\mathtt C 后,直接令j 加一;加入一个\mathtt B 后,j 不变,直接令答案加上对应贡献;加入一个\mathtt A 后,此时两个\mathtt A 中间没有\mathtt C 所以无法操作。
这就产生了新的状态:形如
那么我们考虑
-
加入一个
\mathtt A 是简单的。加入一个\mathtt B 后,我们显然可以直接将\mathtt {BAB} 合并成一个\mathtt B 。若原来
j = 4 ,加入字母后仅看当前串的后缀\mathtt {CABAC} ,我们发现:令第一个\mathtt A 禁止和其他\mathtt A 进行合并,这样一定不劣。如果与其左边的\mathtt A 进行合并,那么不妨直接令第二\mathtt A 替代之进行合并;如果与第二个\mathtt A 右边的\mathtt A 进行合并,那么在该合并中,中间一定存在一个\mathtt C ,那么我们不妨改为将那个\mathtt C 与\mathtt {CABAC} 中第一个\mathtt C 进行合并。所以,我们可以忽略第一个
\mathtt A ,近似地表示成\mathtt {CBAC} ,应转移到f_{i + 1, 4, \mathtt C, 1} 。若
j = 5 ,串变为\mathtt {BCABAC} ,同样地忽略第一个\mathtt A ,那么可以合并\mathtt {BCAB} (忽略第一个\mathtt A 后可以看成\mathtt {BCB} ,又由于两个\mathtt B 中间存在一个\mathtt A 所以可以合并),串变为\mathtt {BAC} 。若
j = 6 ,串变为\mathtt {ABCABAC} ,合并\mathtt {BCAB} 后变为\mathtt {ABAC} 。若
j = 7 ,串变为\mathtt {CABCABAC} ,合并\mathtt {BCAB} 后变为\mathtt {CABAC} ,删掉第一个\mathtt A 后变为\mathtt {CBAC} 。可以发现,j = 7 和j = 4 变成的最终串是相同的。又发现j 拓展到j + 1 时,只是在最前面加了一个字母,影响不大,所以模3 相同的j 转移应该是相同的。 -
对于
j = 4, 7, 10, \dots ,合并次数分别为0, 1, 2, \dots ,最终串为\mathtt {CBAC} ,转移到f_{i + 1, 4, \mathtt C, 1} 。 -
对于
j = 5, 8, 11, \dots ,合并次数分别为1, 2, 3, \dots ,最终串为\mathtt {BAC} ,转移到f_{i + 1, 3, \mathtt C, 1} 。 -
对于
j = 6, 9, 12, \dots ,合并次数分别为1, 2, 3, \dots ,最终串为\mathtt {ABAC} ,这又是一个新的状态,不妨使用f_{i, j, c, 3} 表示这样形如\mathtt {ABACBACBACB \dots} 这样的状态,则转移到f_{i + 1, 4, \mathtt C, 3} 。
最后我们考虑
-
若
j = 3 ,即当前串为\mathtt {ABA} ,加入\mathtt A 是容易的,加入\mathtt {C} 则转移到f_{i + 1, 4, \mathtt C, 3} ;加入\mathtt B 后,显然可以合并\mathtt {BAB} ,串变为\mathtt {AB} ,转移到f_{i + 1, 2, \mathtt B, 0} 。 -
若
j > 3 ,加入\mathtt {A,B,C} 都是容易转移的。
加入完所有字母后,对最终得到的串不断进行操作直到不能操作为止。对于
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define uLL unsigned LL
#define fi first
#define se second
#define mkp make_pair
#define pir pair<ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF :
// *p1++)
template <class T>
const inline void rd(T &x) {
char ch;
bool neg = 0;
while (!isdigit(ch = getchar()))
if (ch == '-')
neg = 1;
x = ch - '0';
while (isdigit(ch = getchar())) x = (x << 1) + (x << 3) + ch - '0';
if (neg)
x = -x;
}
const ll maxn = 3010, mod = 1e9 + 7, inf = 1e9;
ll power(ll a, ll b = mod - 2, ll p = mod) {
ll s = 1;
while (b) {
if (b & 1)
s = 1ll * s * a % p;
a = 1ll * a * a % p, b >>= 1;
}
return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline ll mus(const T x, const _T y) { return x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline void sub(T &x, const _T y) { x = x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y ? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y ? x : y; }
ll n, a[maxn], f[maxn][maxn][3][4], suf[maxn], ans;
char str[maxn];
int main() {
rd(n), scanf("%s", str + 1);
for(ll i = 1; i <= n; i++) a[i] = str[i] - '0';
for(ll c = 0; c < 3; c++)
if(a[1] & (1 << c)) f[1][1][c][0] = 1;
suf[n + 1] = 1;
for(ll i = n; i; i--)
suf[i] = 1ll * suf[i + 1] * __builtin_popcount(a[i]) %mod;
for(ll i = 2; i <= n; i++) {
for(ll j = 1; j < i; j++)
for(ll p = 0; p < 3; p++)
for(ll u = 0; u < 4; u++)
for(ll q = 0; q < 3; q++) {
if(!(a[i] & (1 << q)) || !f[i - 1][j][p][u]) continue;
if(p == q) {
add(ans, 1ll * f[i - 1][j][q][u] * suf[i + 1] %mod);
add(f[i][j][q][u], f[i - 1][j][p][u]);
} else {
ll z = (q == (p + 1) % 3);
if(u == 2) {
if(z) {
add(ans, 1ll * f[i - 1][j][p][2] * suf[i + 1] %mod);
add(f[i][j - 1][q][0], f[i - 1][j][p][2]);
} else {
add(ans, (j - 2) / 3 * 1ll * f[i - 1][j][p][2] %mod * suf[i + 1] %mod);
if(j % 3 == 0) add(f[i][4][q][3], f[i - 1][j][p][2]);
else if(j % 3 == 1) add(f[i][4][q][1], f[i - 1][j][p][2]);
else add(f[i][3][q][1], f[i - 1][j][p][2]);
}
}
if(u == 3) {
if(z) {
add(ans, 1ll * f[i - 1][j][p][3] * suf[i + 1] %mod);
if(j == 3) add(f[i][2][q][0], f[i - 1][j][p][3]);
else add(f[i][j - 1][q][3], f[i - 1][j][p][3]);
} else add(f[i][j + 1][q][3], f[i - 1][j][p][3]);
}
if(u == 0) {
if(z) add(f[i][j + 1][q][0], f[i - 1][j][p][0]);
else {
if(j == 1) add(f[i][j + 1][q][1], f[i - 1][j][p][0]);
else if(j == 2) add(f[i][3][q][3], f[i - 1][j][p][0]);
else add(f[i][j + 1][q][2], f[i - 1][j][p][0]);
}
}
if(u == 1) {
if(z) {
add(ans, 1ll * f[i - 1][j][p][1] * suf[i + 1] %mod);
add(f[i][j - 1][q][j > 2], f[i - 1][j][p][1]);
} else add(f[i][j + 1][q][1], f[i - 1][j][p][1]);
}
}
}
}
for(ll i = 1; i <= n; i++)
for(ll c = 0; c < 3; c++) {
add(ans, (i - 1) / 3 * 1ll * (f[n][i][c][0] + f[n][i][c][1]) %mod);
add(ans, (i - 2) / 3 * 1ll * (f[n][i][c][2] + f[n][i][c][3]) %mod);
}
printf("%d\n", ans);
return 0;
}