有些烦恼,丢掉了,才有登峰造极的机会。
联赛测试 Round 12 装饰
注意到如果我们确定了红色和绿色之后,蓝色的自然而然也就确定了。
故我们考虑去看一组合法的红色和绿色是什么样子的。
一列两个格子,我们可以把他看作三种情况:只有红色,只有绿色,和两个都有。(至于摆放我们是不知道在上还是在下的)
我们把这三种情况分别称为 $1,2,3$。
注意到一种合法的染色,必然是每列都由 $1,2,3$ 中的一个填入,且相邻两个数字不相同。(这个分析一下题面的条件应该是可以得到的)
并且我们发现 $1,2,3$ 填入的数量可以通过输入的 $R,G,B$ 确定。(你写一个三元一次方程就是了)
又可以发现,我们第一列无论 $1,2,3$ ,只要确定了他们各自的填入状态(比如谁在上谁在下)那么后面的填写就不需要再进行讨论了。相当于答案最后乘一个 $2$。
考虑 $1,2,3$ 有多少种填入方法。
注意到,我们可以发现,填入的所有的 $1$ 的之间必然会存在 $2,3$(当然也包括起始和末尾),并且这里面的 $2,3$ 只会以长度为奇数的 $23232$ 或者 $32323$,或者长度为偶数的 $232323$ 存在(可以发现所有长度为偶数的其实本质相同,只需要最后乘二次幂即可)。
考虑去枚举多少个空位填了偶数长度,然后通过列方程的到 $23232$ 和 $32323$ 的填写次数,然后计算一下方案即可。
大抵如下:
int solve(int n)
{
if(n <= 0) return 0;
int ans = 0;
for (int i = 0; i <= n; ++i)
{
//a 12121 b 21212
//a - b = x - y
//a + b + i = n
if(x - y + n - i & 1) continue;
int a = (x - y + n - i) / 2, b = a - x + y;
if(a < 0 || b < 0) continue;
// cerr << a << " " << b << endl;
ans += C(n, a) * 1ll * C(n - a, b) % mod * ksm(2, i) % mod * C(x - a - i + n - 1, n - 1) % mod;
ans %= mod;
}
return ans;
}
int main()
{
freopen("decoration.in", "r", stdin);
freopen("decoration.out", "w", stdout);
cin >> m >> a >> b >> c;
x = m - b, y = m - a, z = m - c;
fact[0] = 1;
for (int i = 1; i <= 2 * m; ++i) fact[i] = 1ll * fact[i - 1] * i % mod;
inv[2 * m] = ksm(fact[2 * m], mod - 2);
for (int i = 2 * m - 1; i >= 0; --i) inv[i] = inv[i + 1] * 1ll * (i + 1) % mod;
int ans = (2ll * solve(z) + solve(z + 1) + solve(z - 1)) % mod;
cout << ans * 2ll % mod << endl;
return 0;
}