zoukankan      html  css  js  c++  java
  • [洛谷P4389]付公主的背包

    传送门

    题目大意

      有(n)类物品,每种物品体积为(V_i),且都有无数多件。

      问你塞满容量为(s)的背包方案数,对于每个(sin [1,m])(m)给定且(leq 10^5),都求出方案数。答案对(998244353)取模。

      (30\%)的数据,(n,mleq 3000)

      (60\%)的数据,纯随机生成;

      (100\%)的数据,(n,mleq 10^5),且一定满足(V_i leq m)

    题解

    30 %

      普通背包随便搞搞,复杂度( ext{O}(nm))

    100 %

      显然对于这类问题我们有一个生成函数的解法:定义每种体积为(k)的物品的生成函数:

    [G_k(x)=1+x^k+x^{2k}+x^{3k}+dotsb=frac{1}{1-x^k} ]

      那么答案的生成函数就是:

    [F(x)=prod_i G_{V_i}(x) ]

      容量为(s)的答案即为([x^s]F(x))

      关键一次多项式乘法的复杂度很高。数据随机还可以乱搞,但不随机会被卡。

      降低复杂度,除了换成点值表示,还可以乘法变加法:我们有(e^acdot e^b=e^{a+b})

      所以将所有(G(x))(ln)得到指数,然后相加可行呢?可是求指数也是个复杂度高的东西,但发现我们实际上(G(x))求的(ln)只与(k)有关,而且是有规律的!

      推导一下:

    [egin{aligned} lnfrac{1}{1-x^k}&=int frac{(dfrac{1}{1-x^k})'}{dfrac{1}{1-x^k}}mathrm dx\ &=int (1+x^k+x^{2k}+dotsb)'(1-x^k)mathrm dx\ &=int (kx^{k-1}+2kx^{2k-1}+dotsb)(1-x^k)mathrm dx\ &=kint (x^{k-1}+x^{2k-1}+dotsb)mathrm dx\ &=k(frac{1}{k}x^k+frac{1}{2k}x^{2k}+dotsb)\ &=x^k+frac{1}{2}x^{2k}+frac{1}{3}x^{3k}dotsb end{aligned} ]

      我们可以在调和级数复杂度求出来所有(ln G_k(x))

      边求边加,最后再多项式(exp)一下就完事了。总复杂度:( ext{O}(nlog n))

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 130000 + 5;
    const int P = 1004535809, g = 3;
    
    int inc(int a, int b) { return (a += b) >= P ? a-P : a; }
    int qpow(int a, int b) {
    	int res = 1;
    	for (int i = a; b; i = 1ll*i*i%P, b >>= 1)
    		if (b & 1) res = 1ll*res*i%P;
    	return res;
    }
    
    int W[maxn << 3], inv[maxn << 2], fac[maxn << 2], ifac[maxn << 2];
    void prework(int n) {
    	for (int i = 1; i < n; i <<= 1) {
    		W[i] = 1;
    		for (int j = 1, Wn = qpow(g, (P-1)/i>>1); j < i; j++) W[i+j] = 1ll*W[i+j-1]*Wn%P;
    	}
    	inv[1] = fac[0] = ifac[0] = 1;
    	for (int i = 2; i < n; i++) inv[i] = 1ll*(P-P/i)*inv[P%i]%P;
    	for (int i = 1; i < n; i++) fac[i] = 1ll*fac[i-1]*i%P, ifac[i] = 1ll*ifac[i-1]*inv[i]%P;
    }
    
    void ntt(int *a, int n, int opt) {
    	static int rev[maxn << 2];
    	for (int i = 1; i < n; i++)
    		if ((rev[i] = rev[i>>1]>>1|(i&1?n>>1:0)) > i) swap(a[i], a[rev[i]]);
    	for (int q = 1; q < n; q <<= 1)
    		for (int p = 0; p < n; p += q << 1)
    			for (int i = 0, t; i < q; i++)
    				t = 1ll*W[q+i]*a[p+q+i]%P, a[p+q+i] = inc(a[p+i], P-t), a[p+i] = inc(a[p+i], t);
    	if (~opt) return;
    	for (int i = 0; i < n; i++) a[i] = 1ll*a[i]*inv[n]%P;
    	reverse(a+1, a+n);
    }
    
    struct poly {
    	vector<int> A;
    	int len;
    	poly(int a0 = 0) : len(1) { A.push_back(a0); }
    	int &operator [] (int i) { return A[i]; }
    	void write() {
    		for (int i = 0; i < len; i++) printf("%d ", A[i]);
    		putchar('
    ');
    	}
    	void load(int *from, int n) {
    		A.resize(len = n);
    		memcpy(&A[0], from, sizeof(int) * len);
    	}
    	void cpyto(int *to, int n) {
    		memcpy(to, &A[0], sizeof(int) * min(len, n));
    	}
    	void resize(int n = 0) {
    		if (!n) { while (len > 1 && !A[len - 1]) len--; A.resize(len); } else A.resize(len = n, 0);
    	}
    } F, G;
    
    poly poly_inv(poly A) {
    	poly B = poly(qpow(A[0], P-2));
    	for (int len = 1; len < A.len; len <<= 1) {
    		static int x[maxn << 2], y[maxn << 2];
    		for (int i = 0; i < len << 2; i++) x[i] = y[i] = 0;
    		A.cpyto(x, len << 1), B.cpyto(y, len);
    		ntt(x, len << 2, 1), ntt(y, len << 2, 1);
    		for (int i = 0; i < len << 2; i++) x[i] = inc(y[i], inc(y[i], P-1ll*x[i]*y[i]%P*y[i]%P));
    		ntt(x, len << 2, -1);
    		B.load(x, len << 1);
    	}
    	return B.resize(A.len), B;
    }
    
    poly operator + (poly A, poly B) {
    	if (A.len < B.len) A.resize(B.len);
    	for (int i = 0; i < B.len; i++) A[i] = inc(A[i], B[i]);
    	return A.resize(), A;
    }
    
    poly operator - (poly A, poly B) {
    	if (A.len < B.len) A.resize(B.len);
    	for (int i = 0; i < B.len; i++) A[i] = inc(A[i], P-B[i]);
    	return A.resize(), A;
    }
    
    int getsize(int n) { int N = 1; while (N < n) N <<= 1; return N; }
    
    poly operator * (poly A, poly B) {
    	static int x[maxn << 2], y[maxn << 2];
    	int len = getsize(A.len + B.len - 1);
    	for (int i = 0; i < len; i++) x[i] = y[i] = 0;
    	A.cpyto(x, A.len), B.cpyto(y, B.len);
    	ntt(x, len, 1), ntt(y, len, 1);
    	for (int i = 0; i < len; i++) x[i] = 1ll*x[i]*y[i]%P;
    	ntt(x, len, -1);
    	return A.load(x, A.len + B.len - 1), A.resize(), A;
    }
    
    poly poly_deri(poly A) {
    	for (int i = 0; i < A.len - 1; i++) A[i] = 1ll*A[i+1]*(i+1)%P;
    	return A[A.len - 1] = 0, A.resize(), A;
    }
    
    poly poly_int(poly A) {
    	for (int i = A.len - 1; i; i--) A[i] = 1ll*A[i-1]*inv[i]%P;
    	return A[0] = 0, A;
    }
    
    poly poly_ln(poly A) {
    	poly B = poly_deri(A) * poly_inv(A);
    	return B.resize(A.len), poly_int(B);
    }
    
    int n;
    
    int main() {
    	scanf("%d", &n); prework((n+1)<<2);
    	G.resize(n+1);
    	for (int i = 1; i <= n; i++) G[i] = 1ll*qpow(2, 1ll*i*(i-1)/2%(P-1))*ifac[i]%P;
    	G[0] = 1;
    	F = poly_ln(G);
    	printf("%d", 1ll*F[n]*fac[n]%P);
    	return 0;
    }
    
  • 相关阅读:
    虚拟机Centos安装docker小记
    Python selenium入门
    selenium Error
    DveOps路线指南
    DevOps
    Go语言常量和变量
    安装Go语言及环境的搭建
    Win10 搭建IIS服务
    linux 上搭建sftp服务
    linux小命令
  • 原文地址:https://www.cnblogs.com/ac-evil/p/12089805.html
Copyright © 2011-2022 走看看