题目传送门
很显然每次填完 L 之后所覆盖的图形为正方形,不然最最后无法填出正方形。现在假设我们已经确定了一个 \(k\) 阶的 L,要求它的方案数。
对于 \([1,k-1]\) 阶 L 的放法,每阶的 \(4\) 种方向都对应着一种方案,但 \(1\) 阶只有 \(4\) 种都是一样的,所以总方案数为 \(4^{k-2}\) 种。
对于 \([k+1,n]\) 阶 L 的放法,设其 \(k\) 阶 L 离上、下、左、右边界的距离分别为 \(a,b,c,d\),那么从中选出那些是覆盖上面的,那些是覆盖左边的,即可唯一确定一种放法,方案数 \(\binom{a+b}{a}\binom{c+d}{c}\)。
枚举 \((a,b)\) 是在 L 的四个角上或四个方向的边上,角的情况下 L 是确定的,直接算就行了。边上的情况中 L 是可以上下或左右平移的,其式子就是组合数的前缀和。记 \(f(n,k)=\sum\limits_{i=0}^k\binom{n}{k}\)。显然可以从 \(f(n,k)\) 转移到 \(f(n,k-1)\) 和 \(f(n,k+1)\)。又有
\[\binom{n}{k}=\binom{n-1}{k-1}+\binom{n-1}{k}
\]
所以
\[f(n,k)=f(n-1,k-1)+f(n-1,k)
\]
\[f(n-1,k)=\frac{f(n,k)+\binom{n-1}{k}}{2}
\]
这样我们就能从 \(f(n,k)\) 转移到 \(f(n-1,k)\) 了。可以观察到总移动次数是 \(O(n)\) 的,直接转移即可。
一些注意的点:
- 角的方案要 \(\times 3\),边的方案要 \(\times 2\)。
- 转移的过程中可能会转移到 \(f(n,k)\) 中 \(k>n\) 的情况,这时候要从 \(f(n,n)=2^n\) 去转移。
Code:
const int N = 2e7 + 10, MOD = 998244353;
int n, a, b, q;
long long jc[N], jny[N], ny[N], pw2[N];
vector < pair <int, int> > vt, pt;
long long C(int x, int y){return jc[y] * jny[x] % MOD * jny[y - x] % MOD;
}
long long gt(int x, int k){if(x < 0)return 0;auto t = (x < k / 2)? make_pair(0, 1ll) : make_pair(k, pw2[k]);for(auto i : vt)if(i.first <= k && abs(t.first - x) > abs(i.first - x))t = i;while(t.first < x)t.first++, t.second = (t.second + C(t.first, k)) % MOD;while(t.first > x)t.second = (t.second - C(t.first, k) + MOD) % MOD, t.first--;pt.push_back(t);return t.second;
}
long long calc(int a, int b, int c, int d){if(a <= 0 || b <= 0 || c > n || d > n)return 0;return C(a - 1, a - 1 + n - c) * C(b - 1, b - 1 + n - d) % MOD;
}
long long calc(int x, int y, int k){int l = max(1, y - k + 2), r = min(n - k + 1, y - 1);if(l > r)return 0;long long t = (gt(r - 1, n - k) - gt(l - 2, n - k) + MOD) % MOD, sum = 0;if(x + k - 1 <= n)sum = (sum + t * C(x - 1, n - k)) % MOD;if(x - k + 1 > 0)sum = (sum + t * C(n - x, n - k)) % MOD;return sum;
}
int main(){ios::sync_with_stdio(0);cin.tie(0);cin >> n >> a >> b >> q;jc[0] = jc[1] = ny[0] = ny[1] = jny[0] = jny[1] = pw2[0] = 1, pw2[1] = 2;for(int i = 2; i <= 2 * n; i++)ny[i] = (MOD - MOD / i) * ny[MOD % i] % MOD, jc[i] = jc[i - 1] * i % MOD, jny[i] = jny[i - 1] * ny[i] % MOD, pw2[i] = pw2[i - 1] * 2 % MOD;int la = n;while(q--){int k;cin >> k;while(la > n - k){la--;for(auto &i : vt)i.second = (i.second + C(i.first, la)) % MOD * ny[2] % MOD;}pt.clear();long long sum = (calc(a, b, k) + calc(b, a, k)) * 2 % MOD;if(k > 1)sum = (sum +(calc(a - k + 1, b - k + 1, a, b) + calc(a - k + 1, b, a, b + k - 1) + calc(a, b - k + 1, a + k - 1, b) + calc(a, b, a + k - 1, b + k - 1)) * 3) % MOD;elsesum = (sum + calc(a, b, a, b)) % MOD;swap(pt, vt);sort(vt.begin(), vt.end());vt.erase(unique(vt.begin(), vt.end()), vt.end());cout << sum * pw2[max(0, k - 2) * 2] % MOD << "\n";}
}