ABC240 G - Teleporting Takahashi 题解
题目简介
给出 \(n(1\leq n \leq 10^7)\)和 \(x,y,z(-10^7\leq x,y,z \leq 10^7)\) ,求长度为 \(n+1\) 的三元组序列 \((x_i,y_i,z_i)(0 \leq i \leq n)\) 满足:
- \((x_0,y_0,z_0) = (0,0,0)\)
- \((x_n,y_n,z_n) = (x,y,z)\)
- \(|x_{i}-x_{i-1}|+|y_{i}-y_{i-1}|+|z_{i}-z_{i-1}| = 1\)
输出方案数对 \(998244353\) 取模的结果。
URL = https://atcoder.jp/contests/abc240/tasks/abc240_g
Hint 1 : 2D
如果我们考虑下列一个简化问题,从 \((0,0)\) 走到 \((x,y)\) ,总共走了\(k\) 步,方案数为多少。
事实上,这个简化版本可以用 \(O(1)\) 的时间复杂度计算。
\(x\) 轴走一步,相当于加上一个向量\((\pm 1,0)\), \(y\) 轴走一步,相当于加上一个向量\((0, \pm 1)\)。
如果考虑将坐标系从 \((x,y)\) 映射到 \((x+y,x-y)\),那么上述四个步骤可以表示为加上向量:\((\pm 1,\pm 1)\)。
因此,将两个维度分别考虑即可,即对于 1D 维度,我们需要求解下列问题:
\(n\) 次操作,每次操作可以\(\pm 1\),问把 \(0\) 变成 \(x\) 的方案数为多少。
- 如果 \(n+x\) 是奇数,方案数为 \(0\)。
- 如果 \(n+x\) 是偶数,方案数为 \(\binom{n}{\frac{n+x}{2}}\)。
组合数公式为:\(\binom{n}{m} = \frac{n!}{m!(n-m)!}\),
对于\(1 \leq n \leq 10^7\),可以考虑预处理 \(n!\) 的逆元(线性筛 + 前缀积),直接套公式计算。
Hint 2 : 枚举
考虑 3D 的问题,我们只需要枚举总共的 \(n\) 步,有 \(i\) 步是给 \(x\) 方向走的,那么剩余的 \(n-i\) 步就是在 \((y,z)\) 这个平面内走的,这就化归到上述的 2D 情况。
对于一个确定的 \(i (0 \leq i \leq n)\),首先要计算在 \(x\) 方向上走 \(i\) 步能否到达预定的数字,这也化归到上述的 1D 情况。此外由于一共进行了\(n\)步,那么需要将先进行的\(i\)步,分配到对应的位置,这些位置的个数为\(\binom{n}{i}\) 。
由于组合数可以 \(O(1)\) 计算,所以本题可以在 \(O(n)\) 的时间复杂度内求解。
solution
时间复杂度:\(O(n)\)
空间复杂度: \(O(n)\)
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int mo = 998244353;
const int N=1e7+10;
int s[N],t[N];
int c(int n,int m) {
int res;
if (n-m>=0 && n>=0 && m>=0) res = s[n]*t[m]%mo*t[n-m]%mo;
else res = 0;
return res;
}
int fun1(int n,int x) {
if ((n+x)%2 != 0) return 0;
return c(n,(n+x)/2);
}
int fun2(int n,int x,int y) {
return fun1(n,x+y)*fun1(n,x-y)%mo;
}
signed main() {
int n,x,y,z; cin>>n>>x>>y>>z;
s[0]=1; for (int i=1;i<=n;i++) s[i] = s[i-1]*i%mo;
t[1]=1; for (int i=2;i<=n;i++) t[i]=mo-mo/i*t[mo%i]%mo;
t[0]=1; for (int i=1;i<=n;i++) t[i]=t[i-1]*t[i]%mo;
int ans = 0;
for (int i=0;i<=n;i++) {
(ans += fun1(i,x) * c(n,i)%mo * fun2(n-i,y,z)%mo)%=mo;
}
cout<<ans<<endl;
return 0;
}