zoukankan      html  css  js  c++  java
  • LOJ 556: 「Antileaf's Round」咱们去烧菜吧

    题目传送门:LOJ #556

    题意简述:

    (m) 种物品,第 (i) 种物品的体积为 (a_i),数量为 (b_i)

    对于 (1le ile n),求出使用这些物品恰好填满容积为 (i) 的背包的方案数。

    两种方案不同当且仅当存在一种物品在两种方案中被选取的数量不同。

    (1le n,mle 10^5)

    题解:

    显然可以 (mathcal{O}(nm)) DP,考虑将 (m) 个阶段的 DP 方程写成卷积形式,则有:

    (egin{aligned}mathbf{OGF}{mathrm{Ans}}&=prod_{i=1}^{m}sum_{j=0}^{b_i}x^{jcdot a_i}\&=prod_{i=1}^{m}frac{1-x^{a_i(b_i+1)}}{1-x^{a_i}}end{aligned})

    如果指数不大就可以分治 NTT + 多项式求逆,但是这里指数太大了,考虑两边取对数:

    (egin{aligned}ln(mathbf{OGF}{mathrm{Ans}})&=sum_{i=1}^{m}left(lnleft(frac{1}{1-x^{a_i}} ight)-lnleft(frac{1}{1-x^{a_i(b_i+1)}} ight) ight)end{aligned})

    根据 (displaystylelnleft(frac{1}{1-ax^k} ight)=sum_{i=1}^{infty}frac{a^i}{i}x^{ik}) 这一结论,继续化简得到:

    (egin{aligned}mathbf{OGF}{mathrm{Ans}}&=expleft(sum_{i=1}^{m}left(sum_{j=1}^{infty}frac{x^{ja_i}}{j}-sum_{j=1}^{infty}frac{x^{ja_i(b_i+1)}}{j} ight) ight)end{aligned})

    把上面的指数 (a_i)(a_i(b_i+1)) 的贡献((pm 1))记录在桶里,然后调和级数加进贡献,最后多项式 (mathrm{Exp}) 解决。

    最后,这题数据可能与题面冲突,总之忽略所有 (a_i=0) 的物品。

    下面是代码,时间复杂度 (mathcal{O}(nlog n+m))

    #include <cstdio>
    #include <algorithm>
    
    typedef long long LL;
    const int Mod = 998244353;
    const int G = 3, iG = 332748118;
    const int MS = 1 << 18;
    const int MN = 100005;
    
    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;
    }
    
    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 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 N, M, buk[MN];
    int A[MS], B[MS];
    
    int main() {
    	Init(MS);
    	scanf("%d%d", &N, &M);
    	for (int i = 1; i <= M; ++i) {
    		int A, B;
    		scanf("%d%d", &A, &B);
    		if (!A) continue;
    		if (!B) B = N;
    		if (A <= N) ++buk[A];
    		if (B + 1 <= N / A) --buk[A * (B + 1)];
    	}
    	Init(MS);
    	for (int i = 1; i <= N; ++i) if (buk[i]) {
    		if (buk[i] < 0) buk[i] += Mod;
    		for (int j = i, k = 1; j <= N; j += i, ++k)
    			A[j] = (A[j] + (LL)buk[i] * Inv[k]) % Mod;
    	}
    	PolyExp(A, N + 1, B);
    	for (int i = 1; i <= N; ++i) printf("%d
    ", B[i]);
    	return 0;
    }
    
  • 相关阅读:
    CH Dream(侠客行)
    EDS(特征)
    EDS(架构)
    通过红外线设备进行TCP/IP互连
    CH Dream(道路)
    北漂实习那些话【一】
    程序员,有时我们应该懂得
    迷茫的IT小小鸟
    《PHP求职宝典》PHP语言基础笔记
    Android中Activity启动模式详解
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/LOJ556.html
Copyright © 2011-2022 走看看