多项式全家桶
对 \(ln\) 的处理是,先求导再积分。(详见付公主的背包)
当我们在对分式求导时,可以把他先化为母函数的无穷级数,然后求导,再化回来。
[ZJOI2019] 开关
不愧是浙江省选,难到让我失去写题解的欲望了。有需求可以看粉兔题解。
[WC2019] 数树
问题0
只用考虑边的交集大小。
问题1
引理: 子集容斥: \(f(S) = \sum_{T \sube S} \sum_{Q \sube T} (-1)^{|T| - |Q|} f(Q)\)
则答案为:
\[\sum_{E2} y^{n - |E1 \and E2|} \\
\sum_{T \sube E2} g(T) \sum_{Q \sube T} (-1)^{|T| - |Q|} y^{n - |Q|} \\
\sum_{T \sube E2} g(T) y^{n - |T|} \sum_{Q \sube T} (-y)^{|T| - |Q|} \\
\sum_{T \sube E2} g(T) y^{n - |T|} (1 - y)^{|T|} \\
\sum_{T \sube E2} y^{k} (1 - y)^{n - k} n^{k-2} \prod_{i=1}^k a_i \\
\frac{(1-y)^n}{n^2} \sum_{T \sube E2} \prod_{i=1}^k \frac{ny}{1 - y} a_i
\]
问题2
先书写最暴力的式子。
\[\sum_{E1}\sum_{E2} y^{n - |E1 \and E2|} \\
\sum_{T} g^2(T)y^{n - |T|} \sum_{Q \sube T} (-y)^{|T| - |Q|} \\
\sum_{T} g^2(T)y^{n - |T|} (1 - y)^{|T|} \\
\sum_{T} y^{k}(1 - y)^{n - k} n^{2k - 4} \prod_{i = 1}^{k} a_i^2 \\
\frac{(1-y)^n}{n^4} \sum_{T} \prod_{i=1}^k \frac{n^2y}{(1-y)} a_i^2 \\
F(x) = \sum_{i=1} \frac{n^2y}{(1-y)i!} i^i x^i \\
\sum_{T} \prod_{i=1}^k \frac{n^2y}{(1-y)} a_i^2 = n! [x^n] \sum_{k=0} \frac{1}{k!} F^k(x) = n! [x^n]e^{F(x)}
\]
[AGC038E] Gachapon
类似开关,也是高妙生成函数题(但好像可以minmax容斥)。
我们定义 \(f_i\) 表示在第 \(i\) 轮停止的概率。
我们钦定第一个最后被选,则他的指数型生成函数为:
\[x\frac{1}{(B_1-1)!}p_1^{B_1}x^{B_{1} - 1} \prod_{i=2}^n (e^{p_ix} - \sum_{j=0}^{B_i-1} \frac{1}{j!} p_i^jx^j)
\]
显然可以背包展开系数为 \(a_{w,t} x^{w} e^{tx}\) 的形式,整理可得:
\[f_{k+1} = \sum a_{w , t} t^{k-w} \frac{k!}{(k-w)!} \\
\]
不妨提出化为组合数的形式。
\[
\sum (w + 1)! a_{w,t} \sum t^{k-w} \binom{k + 1}{k - w}
\\
= \sum
(w + 1)! a_{w,t} \frac{1}{(1 - t)^{w + 2}}
\]
最后得到以上式子,背包的部分我们把钦定的东西拿来一起背包,同时记录以下是否完成钦定就好了。
#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pii pair <int , int>
#define mp make_pair
#define fs first
#define sc second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
//const int Mxdt=100000;
//static char buf[Mxdt],*p1=buf,*p2=buf;
//#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
template <typename T>
void read(T &x) {
x=0;T f=1;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s^'0');s=getchar();}
x *= f;
}
template <typename T>
void write(T x , char s='\n') {
if(x<0) {putchar('-');x=-x;}
if(!x) {putchar('0');putchar(s);return;}
T tmp[25] = {} , t = 0;
while(x) tmp[t ++] = x % 10 , x /= 10;
while(t -- > 0) putchar(tmp[t] + '0');
putchar(s);
}
const int MAXN = 405;
const int mod = 998244353;
inline int Add(int x , int y) {x += y;return x >= mod?x - mod:x;}
inline int Sub(int x , int y) {x -= y;return x < 0?x + mod:x;}
inline int Mul(int x , int y) {return 1ll * x * y % mod;}
int qpow(int a , int b) {
int res = 1;
while(b) {
if(b & 1) res = Mul(res , a);
a = Mul(a , a);
b >>= 1;
}
return res;
}
int fac[MAXN] , finv[MAXN] , n , a[MAXN] , b[MAXN];
int p[MAXN][MAXN] , dp[2][MAXN][MAXN][2] , A , B , PA;
int main() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]),read(b[i]) , A = Add(A , a[i]) , B = Add(B , b[i]);
fac[0] = 1;
int N = 400;
for (int i = 1; i <= N + 1; ++i) fac[i] = Mul(fac[i - 1] , i);
finv[N + 1] = qpow(fac[N + 1] , mod - 2);
for (int i = N + 1; i >= 1; --i) finv[i - 1] = Mul(finv[i] , i);
PA = qpow(A , mod - 2);
for (int i = 1; i <= n; ++i) {
p[i][0] = 1 , p[i][1] = Mul(a[i] , PA);
for (int j = 2; j <= b[i]; ++j) p[i][j] = Mul(p[i][j - 1] , p[i][1]);
}
dp[0][0][0][0] = 1;
for (int i = 1 , preA = a[1] , preB = b[1]; i <= n; ++i , preA += a[i] , preB += b[i]) {
for (int j = preA; j >= 0; --j) for (int k = preB; k >= 0; --k) {
dp[i & 1][j][k][0] = dp[i & 1][j][k][1] = 0;
int op = (i - 1) & 1;
if(j >= a[i]) {
dp[i & 1][j][k][0] = Add(dp[op][j - a[i]][k][0] , dp[i & 1][j][k][0]);
dp[i & 1][j][k][1] = Add(dp[op][j - a[i]][k][1] , dp[i & 1][j][k][1]);
}
for (int w = 0; w < b[i] && w <= k; ++w) {
dp[i & 1][j][k][0] = Add(Mul(dp[op][j][k - w][0] , Mul(Mul(mod - 1 , finv[w]) , p[i][w])) , dp[i & 1][j][k][0]);
dp[i & 1][j][k][1] = Add(Mul(dp[op][j][k - w][1] , Mul(Mul(mod - 1 , finv[w]) , p[i][w])) , dp[i & 1][j][k][1]);
}
if(k >= b[i] - 1) dp[i & 1][j][k][1] = Add(dp[i & 1][j][k][1] , Mul(dp[op][j][k - (b[i] - 1)][0] , Mul(p[i][b[i]] , finv[b[i] - 1])));
}
}
int ans = 0;
for (int t = 0; t < A; ++t) for (int w = 0; w <= B; ++w) {
ans = Add(ans , Mul(fac[w + 1] , Mul(dp[n & 1][t][w][1] , qpow(qpow(Sub(1 , Mul(t , PA)) , w + 2) , mod - 2))));
}
write(ans);
return 0;
}
相关知识以后补,先存份代码。
#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pii pair <int , int>
#define mp make_pair
#define fs first
#define sc second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
//const int Mxdt=100000;
//static char buf[Mxdt],*p1=buf,*p2=buf;
//#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
template <typename T>
void read(T &x) {
x=0;T f=1;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s^'0');s=getchar();}
x *= f;
}
template <typename T>
void write(T x , char s='\n') {
if(x<0) {putchar('-');x=-x;}
if(!x) {putchar('0');putchar(s);return;}
T tmp[25] = {} , t = 0;
while(x) tmp[t ++] = x % 10 , x /= 10;
while(t -- > 0) putchar(tmp[t] + '0');
putchar(s);
}
const int MAXN = 2e6 + 5;
const int mod = 998244353;
inline int Add(int x , int y) {x += y;return x >= mod?x - mod:x;}
inline int Sub(int x , int y) {x -= y;return x < 0?x + mod:x;}
inline int Mul(int x , int y) {return 1ll * x * y % mod;}
inline int qpow(int a , int b) {
int res = 1;
while(b) {
if(b & 1) res = Mul(res , a);
a = Mul(a , a);
b >>= 1;
}
return res;
}
namespace Poly_Family {
inline int Cipolla(int n , int mod) {
if(!n) return 0;
if(qpow(n , (mod - 1) / 2) != 1) return -1;
int a = 1;
while(1) {
a = rand() % mod;
if(a && qpow(Sub(Mul(a , a) , n) , (mod - 1) / 2) != 1) break;
}
const int I_P = Sub(Mul(a , a) , n);
pii A = mp(a , 1) , res = mp(1 , 0);
int b = (mod + 1) / 2;
while(b) {
if(b & 1) {
pii tmp;
tmp.fs = Add(Mul(res.fs , A.fs) , Mul(I_P , Mul(res.sc , A.sc)));
tmp.sc = Add(Mul(res.fs , A.sc) , Mul(res.sc , A.fs));
res = tmp;
}
pii tmp;
tmp.fs = Add(Mul(A.fs , A.fs) , Mul(I_P , Mul(A.sc , A.sc)));
tmp.sc = Add(Mul(A.fs , A.sc) , Mul(A.sc , A.fs));
A = tmp;
b >>= 1;
}
int x = res.fs , y = Sub(0 , x);
return min(x , y);
}
#define poly vector <int>
#define Len(x) (int)x.size()
int r[MAXN << 2];
poly w[2][23];
inline void pre(int op) {
for (int t = 1; t <= 22; ++t) {
w[op][t].resize(1 << t);
int k = (1 << (t - 1));
int ori = qpow(3 , (op == 1)?(mod - 1) / (k << 1):(mod - 1) - (mod - 1) / (k << 1));
int now = 1;
for (int j = 0; j < k; ++j) {
w[op][t][j] = now;
now = Mul(now , ori);
}
}
}
inline void Resize(poly &F , int n) {F.resize(n , 0);}
inline void NTT(poly &F , int op) {
if(op == -1) op = 0;
int N = Len(F);
for (int i = 0; i < N; ++i) if(i < r[i]) swap(F[i] , F[r[i]]);
for (int k = 1 , t = 1; k < N; k <<= 1 , t ++) {
for (int i = 0; i < (N >> t); ++i) {
for (int j = 0; j < k; ++j) {
int cur = Mul(w[op][t][j] , F[(i << t) ^ k ^ j]);
F[(i << t) ^ j ^ k] = Sub(F[(i << t) ^ j] , cur);
F[(i << t) ^ j] = Add(F[(i << t) ^ j] , cur);
}
}
}
if(op == 0) {
int D = qpow(N , mod - 2);
for (int i = 0; i < N; ++i) F[i] = Mul(F[i] , D);
}
}
inline poly operator - (poly F , poly G) {
int n = Len(F) , m = Len(G) , N = max(n , m);
Resize(F , N) , Resize(G , N);
for (int i = 0; i < Len(F); ++i) F[i] = Sub(F[i] , G[i]) % mod;
return F;
}
inline poly operator + (poly F , poly G) {
int n = Len(F) , m = Len(G) , N = max(n , m);
Resize(F , N) , Resize(G , N);
for (int i = 0; i < Len(F); ++i) F[i] = Add(F[i] , G[i]) % mod;
return F;
}
inline poly operator * (poly F , poly G) {
poly FG;
int n = Len(F) , m = Len(G) , rl = n + m - 1 , N = 1;
while(N < rl) N <<= 1;
Resize(F , N) , Resize(G , N) , Resize(FG , N);
for (int i = 1; i < N; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1)?(N >> 1):0);
NTT(F , 1) , NTT(G , 1);
for (int i = 0; i < N; ++i) FG[i] = Mul(F[i] , G[i]);
NTT(FG , -1);
Resize(FG , rl);
return FG;
}
inline poly Deri(poly F) {
for (int i = 0; i < Len(F) - 1; ++i) F[i] = Mul(F[i + 1] , i + 1);
F[Len(F) - 1] = 0;
return F;
}
inline poly Integ(poly F) {
Resize(F , Len(F) + 1);
for (int i = Len(F) - 1; i >= 1; --i) F[i] = Mul(F[i - 1] , qpow(i , mod - 2));
F[0] = 0;
return F;
}
inline poly Inv(poly F) {
poly G;
G.resize(1);
G[0] = qpow(F[0] , mod - 2);
for (int k = 2; k <= 2 * Len(F); k <<= 1) {
poly A = F;
Resize(A , k);
Resize(G , k);
for (int i = 1; i < k; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1)?(k >> 1):0);
NTT(G , 1);
poly tmp;Resize(tmp , k);
for (int i = 0; i < Len(G); ++i) tmp[i] = Mul(G[i] , G[i]);
NTT(tmp , -1) , NTT(G , -1);
tmp = tmp * A;
Resize(tmp , k);
for (int i = 0; i < Len(G); ++i) G[i] = Mul(G[i] , 2);
G = G - tmp;
}
return G;
}
inline poly operator / (poly F , poly G) {
reverse(F.begin() , F.end());
reverse(G.begin() , G.end());
int n = Len(F) , m = Len(G);
int N = n - m + 1;
Resize(G , N);
G = Inv(G);
poly Q = F * G;Resize(Q , N);
reverse(Q.begin() , Q.end());
return Q;
}
inline poly Ln(poly F) {
poly G = Integ(Inv(F) * Deri(F));
return G;
}
inline poly Exp(poly F) {
poly f;Resize(f , 1);
f[0] = 1;
for (int k = 2; k <= 2 * Len(F); k <<= 1) {
poly A = F;
Resize(A , k);
A = A - Ln(f);
A[0] = Add(A[0] , 1);
f = f * A;
Resize(f , k);
}
return f;
}
inline poly Qpow(poly F , int k1 , int k2 , int p) {
int l = -1;
for (int i = 0; i < Len(F); ++i) if(F[i]) {
l = i;
break;
}
if(l == -1) return F;
if((LL)l * k1 + p * mod * (l > 0) >= Len(F)) {
for (int i = 0; i < Len(F); ++i) F[i] = 0;
return F;
}
poly G;G.resize(Len(F) - l);
for (int i = 0; i < Len(G); ++i) G[i] = F[i + l];
int v = G[0] , iv = qpow(v , mod - 2);
for (int i = 0; i < Len(G); ++i) G[i] = Mul(G[i] , iv);
G = Ln(G),Resize(G , Len(F) - l);
for (int i = 0; i < Len(G); ++i) G[i] = Mul(G[i] , k1);
G = Exp(G),Resize(G , Len(F) - l);
v = qpow(v , k2);
for (int i = 0; i < Len(G); ++i) G[i] = Mul(G[i] , v);
l *= k1;
for (int i = 0; i < l; ++i) F[i] = 0;
for (int i = l; i < Len(F); ++i) F[i] = G[i - l];
return F;
}
inline poly Sqrt(poly F) {
poly f;Resize(f , 1);
f[0] = Cipolla(F[0] , mod);
if(f[0] == -1) return f;
int inv2 = (mod + 1) >> 1;
for (int k = 2; k <= 2 * Len(F); k <<= 1) {
poly A = F;
Resize(A , k);
poly tmp = Inv(f);
Resize(tmp , k);
f = f + tmp * A;
Resize(f , k);
for (int i = 0; i < Len(f); ++i) f[i] = Mul(f[i] , inv2);
Resize(f , k);
}
return f;
}
}
using namespace Poly_Family;
poly F;
int n;
int main() {
pre(0) , pre(1);
int n , k1 = 0 , k2 = 0 , p = 0;
read(n);
char s=getchar();
while(s<'0'||s>'9') s=getchar();
while(s>='0'&&s<='9') {p |= (k1 * 10ll + (s ^ '0') >= mod) , k1 = Add(Mul(k1 , 10) , s ^ '0') , k2 = (k2 * 10ll % (mod - 1) + (s ^ '0')) % (mod - 1);s=getchar();}
Resize(F , n);
for (int i = 0; i < n; ++i) read(F[i]);
F = Qpow(F , k1 , k2 , p);
for (int i = 0; i < Len(F); ++i) write(F[i] , (i!=Len(F))?' ':'\n');
return 0;
}