考虑只考虑二维:
\(\sum \binom{x + y + 2k}{x+i,y + k - i,k - i}\\=\sum \binom{x+y+2k}{x+k}\times\binom{x+k}{x+i}\times\binom{y+k}{i}\)
即考虑枚举二维上如何操作,考虑其共走了\(x + y + 2k\)步,
先枚举第一维上的正方向,然后枚举第二维正方向的位置,然后枚举第二维回退的方向位置。
考虑 \(= \binom{x + y + 2k}{x+ k}\times \sum\binom{x+k}{x + i} \times \binom{y + k}{i} = \binom{x + y + 2k}{x + k} \times \binom{x + y + 2k}{x + y + k}\)
那么第三维的处理是简单的。
在化简过程中共使用了\(2\)次范德蒙德卷积
复杂度\(O(n)\)。
点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 10000010, MOD = 998244353;
long long fac[N], inv[N], ans, n, X, Y, Z;
inline long long C (long long n, long long m) {
if (n < m || n < 0 || m < 0) return 0;
return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
inline long long solve (long long n, long long m) {
if (n < m || (n - m) & 1) return 0;
return C(n, m + (n - m) / 2);
}
int main () {
scanf("%lld%lld%lld%lld", &n, &X, &Y, &Z);
fac[0] = fac[1] = inv[1] = inv[0] = 1;
for (long long i = 2; i <= n; i ++) {
fac[i] = i * fac[i - 1] % MOD;
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}
for (long long i = 2; i <= n; i ++)
inv[i] = inv[i] * inv[i - 1] % MOD;
for (long long i = 0; i <= n; i ++) {
long long x = X + Y, y = X - Y;
ans = (ans + solve(i, x) * solve(i, y) % MOD * C(n, i) % MOD * solve(n - i, Z) % MOD) % MOD;
}
printf("%lld", ans);
return 0;
}
附:
发现上面的做法太 \(dead-do\) 了。
这里给一个官方题解的精妙做法:
-
先考虑第一维;
易得出在一维上有:
\(f_1(N,X) = \binom{N}{\frac{N + X}{2}}\) -
再考虑二维情况:
考虑转变二维坐标系为:
\((x,y) \to (x + y,x - y)\)
那么发现四种操作分别为:
\((x,y) \to (x + 1,y + 1)\)
\((x,y) \to (x + 1,y - 1)\)
\((x,y) \to (x - 1,y + 1)\)
\((x,y) \to (x - 1,y - 1)\)
那么此时的好处就是 \(x,y\) 二维均解放了,那么\(f_2(N,X,Y) = f_1(N,X)f_1(N,Y)\).
- 三维情况
此时是简单的。
只要考虑枚举\(X,Y\)两维用了多少即可。