[多项式] 洛谷P7493 旅人1969
作者:互联网
题目描述
一条笔直的公路上有 \(n\) 个旅店,第 \(i\) 个旅店的坐标是 \(i\),每一天早上从旅店出发走最多 \(m\) 个距离,同时固定给你一个常数 \(k\)。
给定 \(q\) 组询问,每次给定 \(u,v\),求早上从旅店 \(u\) 出发到旅店 \(v\),途径不超过 \(k\) 个旅店(不含起点 \(u\))且行走方向不变的方案数。两种方案不同当且仅当存在一个不同的旅店选择,答案对 \(998244353\) 取模。
对于所有数据,\(n,q\leq 10^5\) ,\(m,k\leq 10^4\) ,\(mk\leq 10^5\) ,\(u,v\leq n\)。
题解
设 \(dp[n][k]\) 表示间隔 \(n\) 个距离,在 \(k\) 个旅店停留的方案数。则有
\[dp[k][n]=dp[k][n-1]+dp[k-1][n-1]-dp[k-1][n-m-1] \]设 \(F_k\) 是 \(dp[k][n]\) 的普通型生成函数,即 \(F_k=\sum_{n=0}^{\infty}dp[k][n]x^n\),则
\[F_k=xF_k+xF_{k-1}-x^{m+1}F_{k-1}\\ (1-x)F_k=x(1-x^m)F_{k-1}\\ F_k=\frac{x(1-x^m)F_{k-1}}{1-x}\\ F_k=\left(\frac{x(1-x^m)}{1-x}\right)^k \]则 \(ans=[x^n]\sum_{k=0}^KF_k\)。
\[ans=[x^n]\sum_{k=0}^KF_k=[x^n]\sum_{k=0}^K\left(\frac{x(1-x^m)}{1-x}\right)^k=[x^n]\frac{1-\left(\frac{x(1-x^m)}{1-x}\right)^{K+1}}{1-\frac{x(1-x^m)}{1-x}}\\ =[x^n]\frac{(1-x)^{K+1}-x^{K+1}(1-x^m)^{K+1}}{(1-x)^{K+1}-x(1-x^m)(1-x)^K}=[x^n]\frac{(1-x)^{K+1}-(x-x^{m+1})^{K+1}}{(1-x)^K[(1-x)-x(1-x^m)]}\\ =[x^n]\frac{(1-x)^{K+1}-(x-x^{m+1})^{K+1}}{(1-x)^K(1-2x+x^{m+1})}\\ \]注意到分子分母的最高次项都是 \(O(mk)\) 级别的,而 \(mk\leq 10^5\),所以可以使用二项式定理把分子分母展开,对分母作多项式求逆,再和分子作卷积,即可求得 \(n\) 次项前的系数。时间复杂度 \(O(mk\log mk)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType& T) {
elemType X = 0, w = 0; char ch = 0;
while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
T = (w ? -X : X);
}
LL ExPow(LL b, LL n, LL MOD) {//b^n mod MOD
if (MOD == 1) return 0;
LL x = 1;
LL Power = b % MOD;
while (n) {
if (n & 1) x = x * Power % MOD;
Power = Power * Power % MOD;
n >>= 1;
}
return x;
}
const int maxn = 270000;
namespace Poly {
int r[maxn];
LL buf[maxn], buf1[maxn], buf2[maxn], buf3[maxn], buf4[maxn];
int L, limit;
const LL P = 998244353, G = 3, Gi = 332748118;
LL pinv(LL x) { return ExPow(x, P - 2, P); }
//快速数论变换 type=1:正变换 type=-1:逆变换
void NTT(LL* A, int type) {
for (int i = 0; i < limit; i++)
if (i < r[i]) swap(A[i], A[r[i]]);
for (int mid = 1; mid < limit; mid <<= 1) {
LL Wn = ExPow(type == 1 ? G : Gi, (P - 1) / (mid << 1), P);
for (int j = 0; j < limit; j += (mid << 1)) {
LL w = 1;
for (int k = 0; k < mid; k++, w = (w * Wn) % P) {
int x = A[j + k], y = w * A[j + k + mid] % P;
A[j + k] = (x + y) % P;
A[j + k + mid] = (x - y + P) % P;
}
}
}
if (type == 1) return;
LL inv_limit = pinv(limit);
for (int i = 0; i < limit; ++i)
A[i] = A[i] * inv_limit % P;
}
//多项式卷积 a(x): N-1次多项式 b(x): M-1次多项式
void Conv(LL* A, int N, LL* B, LL M, LL* C) {
L = 0; limit = 1;
while (limit <= N + M) limit <<= 1, L++;
for (int i = 0; i < limit; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
NTT(A, 1); NTT(B, 1);
for (int i = 0; i < limit; i++) C[i] = A[i] * B[i] % P;
NTT(C, -1);
}
//多项式求逆 F*G=1 mod x^n
void PolyInv(LL* F, LL* G, int N) {
if (N == 1) { G[0] = pinv(F[0]);return; }
PolyInv(F, G, (N + 1) >> 1);
for (limit = 1; limit <= (N << 1); limit <<= 1);
for (int i = 0; i < limit; ++i) {
r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (limit >> 1) : 0);
buf[i] = (i < N ? F[i] : 0);
}
NTT(buf, 1);NTT(G, 1);
for (int i = 0; i < limit; ++i)
G[i] = (2LL - buf[i] * G[i] % P + P) % P * G[i] % P;
NTT(G, -1);
fill(G + N, G + limit, 0);
}
}
LL F[maxn], G[maxn], H[maxn];
int N, M, K, Q;
LL Inv[100010], Fact[100010], FInv[100010];
const LL MOD = 998244353LL;
void Init(int n) {
Inv[1] = Fact[0] = Fact[1] = FInv[0] = FInv[1] = 1;
for (int i = 2;i <= n;++i) {
Inv[i] = ((-(MOD / i) * Inv[MOD % i]) % MOD + MOD) % MOD;
Fact[i] = Fact[i - 1] * i % MOD;
FInv[i] = FInv[i - 1] * Inv[i] % MOD;
}
}
inline LL C(LL n, LL k) {
return Fact[n] * FInv[k] % MOD * FInv[n - k] % MOD;
}
int main() {
Read(N);Read(M);Read(K);Read(Q);
Init(K + 1);
for (int i = 0;i <= K + 1;++i) {
if (i & 1) F[i] = (F[i] + (MOD - C(K + 1, i)) % MOD) % MOD;
else F[i] = (F[i] + C(K + 1, i)) % MOD;
if ((K + 1 - i) & 1)
F[(M + 1) * (K + 1 - i) + i] = (F[(M + 1) * (K + 1 - i) + i] + C(K + 1, i)) % MOD;
else
F[(M + 1) * (K + 1 - i) + i] = ((F[(M + 1) * (K + 1 - i) + i] - C(K + 1, i)) % MOD + MOD) % MOD;
}
for (int i = 0;i <= K;++i) {
if (i & 1) {
G[i] = ((G[i] - C(K, i)) % MOD + MOD) % MOD;
G[i + 1] = (G[i + 1] + C(K, i) * 2LL % MOD) % MOD;
G[i + M + 1] = ((G[i + M + 1] - C(K, i)) % MOD + MOD) % MOD;
}
else {
G[i] = (G[i] + C(K, i)) % MOD;
G[i + 1] = ((G[i + 1] - C(K, i) * 2LL % MOD) % MOD + MOD) % MOD;
G[i + M + 1] = (G[i + M + 1] + C(K, i)) % MOD;
}
}
Poly::PolyInv(G, H, N);
Poly::Conv(F, (M + 1) * (K + 1) + 1, H, N, F);
while(Q--){
int u, v;Read(u);Read(v);
printf("%lld\n", F[v - u]);
}
return 0;
}
标签:洛谷,1969,int,LL,limit,maxn,P7493,frac,dp 来源: https://www.cnblogs.com/AEMShana/p/14639899.html