zoukankan      html  css  js  c++  java
  • Comet 67E: ffort

    题目传送门:Comet 67E

    用了个傻逼做法 A 了这题,欢迎观赏睿智做法!

    题意简述:

    题目说得很清楚了(这次是我不想写了)。

    题解:

    为了方便,令 (m) 为敌人数,(n) 为己方士兵种数。设 (mathbf{Ans}) 为答案,则有:

    [egin{aligned}mathbf{Ans}&=sum_{a=1}^{infty}([x^a]G)cdotinom{a-1}{m-1}\&=sum_{a=0}^{infty}!left([x^{a}]dfrac{G}{x} ight)!cdotinom{a}{hat m}\&=frac{1}{hat m!}sum_{i=0}^{infty}([x^i]F)i^{underline{hat m}}\end{aligned} ]

    意即枚举 (a) 为打出的伤害数,则将这些伤害分配给敌人的方法数为 (dbinom{a-1}{m-1})

    其中 (G) 为给己方士兵分配伤害的方案数的 (mathbf{OGF}),即 (displaystyle G=prod_{i=1}^{n}left[mathbf{OGF}left{0,underset{b_i}{underbrace{1,ldots,1}} ight} ight]^{a_i})

    ([x^a]G) 就为将伤害分配给己方士兵的方案数。

    接下来令 (hat m=m-1)(F=dfrac{G}{x}),变换求和指标并提出 (dfrac{1}{hat m!}),留下下降幂形式。


    下降幂经常出现在多次求导后的多项式中,即 (displaystyle f^{(k)}(x)=sum_{i=k}^{infty}f_ii^{underline{k}}cdot x^{i-k})

    那么 (displaystylesum_{i=0}^{infty}f_ii^{underline{hat m}}=f^{(hat m)}(1))

    据此,则有:

    [mathbf{Ans}=frac{1}{hat m!}F^{(m)}(1) ]

    考虑 (displaystyle F=frac{1}{x}prod_{i=1}^{n}left[mathbf{OGF}left{0,underset{b_i}{underbrace{1,ldots,1}} ight} ight]^{a_i})(hat m) 阶导:

    • 对于 (displaystyle t=prod_{i=1}^{n}t_i)(k) 阶导,重复使用乘法法则 ((fg)'=f'g+fg') 即可得出:
    • (displaystyle t^{(k)}=sum_{a_1+a_2+cdots+a_n=k}inom{k}{a_{1ldots n}}prod_{i=1}^{n}t_i^{(a_i)}),其中 (dbinom{k}{a_{1ldots n}}) 即为多重组合数。
    • 从生成函数的角度看来,即 (displaystyle t^{(k)}=k![z^k]prod_{i=1}^{n}sum_{j=0}^{infty}frac{t_i^{(j)}}{j!}z^j),即每个 ({t_i^{(0)},t_i^{(1)},ldots}) 的二项卷积。

    (f_i=mathbf{OGF}left{0,underset{b_i}{underbrace{1,ldots,1}} ight}) ,特别地 (f_0=dfrac{1}{x})(a_0=1),那么有 (displaystyle F=prod_{i=0}^{n}f_i^{a_i})

    于是:

    [egin{aligned}mathbf{Ans}&=frac{1}{hat m}F^{(m)}(1)\&=frac{1}{hat m}left(hat m!left[z^{hat m} ight]prod_{i=0}^{n}left(sum_{j=0}^{infty}frac{f_i^{(j)}}{j!}z^{j} ight)^{a_i} ight)(1)\&=[z^m]prod_{i=0}^{n}left(sum_{j=0}^{infty}frac{f_i^{(j)}(1)}{j!}z^j ight)^{a_i}end{aligned} ]

    因为 (n imes mle 10^5),所以后面只要算出 (dfrac{f_i^{(j)}(1)}{j!})(0le ile n)(0le jle m)),然后多项式快速幂暴力乘即可。


    接下来考虑如何计算 (dfrac{f_i^{(j)}(1)}{j!})

    对于 (f_0=dfrac{1}{x}),有 (left(dfrac{1}{x} ight)^{(k)}(1)=(-1)^kk!),所以 (dfrac{f_0^{(j)}(1)}{j!}=(-1)^j)

    对于 (f_i=mathbf{OGF}left{0,underset{b_i}{underbrace{1,ldots,1}} ight}),稍加推导可以得到:

    • (f_i^{(0)}(1)),即 (f_i(1)),等于 (b_i)(显然)。
    • 对于 (jge1),有 (f_i^{(j)}(1)=dfrac{(b_i+1)^{underline{j+1}}}{j+1})(证明略),于是 (dfrac{f_i^{(j)}(1)}{j!}=dfrac{(b_i+1)^{underline{j+1}}}{(j+1)!}) 可以递推求出。

    那么这题就做完了,代码如下,复杂度 (mathcal O(nmlog m))

    #include <cstdio>
    #include <algorithm>
    
    typedef long long LL;
    const int Mod = 998244353;
    const int G = 3, iG = 332748118;
    const int MS = 1 << 19;
    
    inline int qPow(int b, int e) {
    	int a = 1;
    	for (; e; e >>= 1, b = (LL)b * b % Mod)
    		if (e & 1) a = (LL)a * b % Mod;
    	return a;
    }
    
    inline int gInv(int b) { return qPow(b, Mod - 2); }
    
    int Inv[MS], Fac[MS], iFac[MS];
    
    inline void Init(int N) {
    	Fac[0] = 1;
    	for (int i = 1; i < N; ++i) Fac[i] = (LL)Fac[i - 1] * i % Mod;
    	iFac[N - 1] = gInv(Fac[N - 1]);
    	for (int i = N - 1; i >= 1; --i) iFac[i - 1] = (LL)iFac[i] * i % Mod;
    	for (int i = 1; i < N; ++i) Inv[i] = (LL)Fac[i - 1] * iFac[i] % Mod;
    }
    
    inline int Binom(int N, int M) {
    	if (M < 0 || M > N) return 0;
    	return (LL)Fac[N] * iFac[M] % Mod * iFac[N - M] % Mod;
    }
    
    int Sz, InvSz, R[MS];
    
    inline int getB(int N) { int Bt = 0; while (1 << Bt < N) ++Bt; return Bt; }
    
    inline void InitFNTT(int N) {
    	int Bt = getB(N);
    	if (Sz == (1 << Bt)) return ;
    	Sz = 1 << Bt, InvSz = Mod - (Mod - 1) / Sz;
    	for (int i = 1; i < Sz; ++i) R[i] = R[i >> 1] >> 1 | (i & 1) << (Bt - 1);
    }
    
    inline void FNTT(int *A, int Ty) {
    	for (int i = 0; i < Sz; ++i) if (R[i] < i) std::swap(A[R[i]], A[i]);
    	for (int j = 1, j2 = 2; j < Sz; j <<= 1, j2 <<= 1) {
    		int wn = qPow(~Ty ? G : iG, (Mod - 1) / j2), w, X, Y;
    		for (int i = 0, k; i < Sz; i += j2) {
    			for (k = 0, w = 1; k < j; ++k, w = (LL)w * wn % Mod) {
    				X = A[i + k], Y = (LL)w * A[i + j + k] % Mod;
    				A[i + k] -= (A[i + k] = X + Y) >= Mod ? Mod : 0;
    				A[i + j + k] += (A[i + j + k] = X - Y) < 0 ? Mod : 0;
    			}
    		}
    	}
    	if (!~Ty) for (int i = 0; i < Sz; ++i) A[i] = (LL)A[i] * InvSz % Mod;
    }
    
    inline void PolyConv(int *_A, int N, int *_B, int M, int *_C) {
    	static int A[MS], B[MS];
    	InitFNTT(N + M - 1);
    	for (int i = 0; i < N; ++i) A[i] = _A[i];
    	for (int i = N; i < Sz; ++i) A[i] = 0;
    	for (int i = 0; i < M; ++i) B[i] = _B[i];
    	for (int i = M; i < Sz; ++i) B[i] = 0;
    	FNTT(A, 1), FNTT(B, 1);
    	for (int i = 0; i < Sz; ++i) A[i] = (LL)A[i] * B[i] % Mod;
    	FNTT(A, -1);
    	for (int i = 0; i < N + M - 1; ++i) _C[i] = A[i];
    }
    
    inline void PolyInv(int *_A, int N, int *_B) {
    	static int A[MS], B[MS], tA[MS], tB[MS];
    	for (int i = 0; i < N; ++i) A[i] = _A[i];
    	for (int i = N, B = getB(N); i < 1 << B; ++i) A[i] = 0;
    	B[0] = gInv(A[0]);
    	for (int L = 1; L < N; L <<= 1) {
    		int L2 = L << 1, L4 = L << 2;
    		InitFNTT(L4);
    		for (int i = 0; i < L2; ++i) tA[i] = A[i];
    		for (int i = L2; i < Sz; ++i) tA[i] = 0;
    		for (int i = 0; i < L; ++i) tB[i] = B[i];
    		for (int i = L; i < Sz; ++i) tB[i] = 0;
    		FNTT(tA, 1), FNTT(tB, 1);
    		for (int i = 0; i < Sz; ++i) tB[i] = tB[i] * (2 - (LL)tA[i] * tB[i] % Mod + Mod) % Mod;
    		FNTT(tB, -1);
    		for (int i = 0; i < L2; ++i) B[i] = tB[i];
    	}
    	for (int i = 0; i < N; ++i) _B[i] = B[i];
    }
    
    inline void PolyLn(int *_A, int N, int *_B) {
    	static int tA[MS], tB[MS];
    	for (int i = 1; i < N; ++i) tA[i - 1] = (LL)_A[i] * i % Mod;
    	PolyInv(_A, N - 1, tB);
    	InitFNTT(N + N - 3);
    	for (int i = N - 1; i < Sz; ++i) tA[i] = 0;
    	for (int i = N - 1; i < Sz; ++i) tB[i] = 0;
    	FNTT(tA, 1), FNTT(tB, 1);
    	for (int i = 0; i < Sz; ++i) tA[i] = (LL)tA[i] * tB[i] % Mod;
    	FNTT(tA, -1);
    	_B[0] = 0;
    	for (int i = 1; i < N; ++i) _B[i] = (LL)tA[i - 1] * Inv[i] % Mod;
    }
    
    inline void PolyExp(int *_A, int N, int *_B) {
    	static int A[MS], B[MS], tA[MS], tB[MS];
    	for (int i = 0; i < N; ++i) A[i] = _A[i];
    	for (int i = N, B = getB(N); i < 1 << B; ++i) A[i] = 0;
    	B[0] = 1;
    	for (int L = 1; L < N; L <<= 1) {
    		int L2 = L << 1, L4 = L << 2;
    		for (int i = L; i < L2; ++i) B[i] = 0;
    		PolyLn(B, L2, tA);
    		InitFNTT(L4);
    		for (int i = 0; i < L2; ++i) tA[i] = (!i + A[i] - tA[i] + Mod) % Mod;
    		for (int i = L2; i < Sz; ++i) tA[i] = 0;
    		for (int i = 0; i < L; ++i) tB[i] = B[i];
    		for (int i = L; i < Sz; ++i) tB[i] = 0;
    		FNTT(tA, 1), FNTT(tB, 1);
    		for (int i = 0; i < Sz; ++i) tA[i] = (LL)tA[i] * tB[i] % Mod;
    		FNTT(tA, -1);
    		for (int i = 0; i < L2; ++i) B[i] = tA[i];
    	}
    	for (int i = 0; i < N; ++i) _B[i] = B[i];
    }
    
    int M, N;
    int Ans[MS], Tmp[MS];
    
    int main() {
    	scanf("%d%d", &M, &N), --M;
    	Init(M + 2);
    	for (int i = 0; i <= M; ++i) Ans[i] = i & 1 ? Mod - 1 : 1;
    	while (N--) {
    		int a, b;
    		scanf("%d%d", &a, &b);
    		Tmp[0] = 1;
    		int coef = (LL)(b + 1) * gInv(b) % Mod;
    		for (int i = 1; i <= M; ++i) {
    			coef = (LL)coef * (b - i + 1) % Mod * Inv[i + 1] % Mod;
    			Tmp[i] = coef;
    		}
    		PolyLn(Tmp, M + 1, Tmp);
    		for (int i = 0; i <= M; ++i) Tmp[i] = (LL)Tmp[i] * a % Mod;
    		PolyExp(Tmp, M + 1, Tmp);
    		int qwq = qPow(b, a);
    		for (int i = 0; i <= M; ++i) Tmp[i] = (LL)Tmp[i] * qwq % Mod;
    		PolyConv(Ans, M + 1, Tmp, M + 1, Ans);
    	}
    	int tAns = Ans[M];
    	printf("%d
    ", tAns);
    	return 0;
    }
    
  • 相关阅读:
    [转]拓扑排序
    [转]C++ string学习
    二叉树的前序遍历
    My Solution to Lowest Common Ancestor of a Binary Tree Part I(TopDown Approach)
    求二叉树节点总数
    二叉树的中序遍历
    轻松搞定面试中的二叉树题目
    VS2005 CrystalReport开发Web应用
    ASP.NET 2.0移动开发入门之使用模拟器
    [原创]Ajax UpLoadFile 多个大文件上传控件,已更新。
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/11565417.html
Copyright © 2011-2022 走看看