[洛谷4389] 付公主的背包

题目链接

洛谷:https://www.luogu.org/problemnew/show/P4389

Solution

挺巧妙的题。

对于每件物品可以看成无穷多个,背包转移可以写成卷积的形式,对于质量为(v)的物品,写成生成函数就是:

[F(x)=sum_{i=0}^{+infty}x^{vi} ]

然后有(1e5)个这样的东西,乘起来就是答案,复杂度(O(mnlog n))

但这样显然过不了,我们把上面的函数变一下:

[F(x)=sum_{i=0}^{+infty}x^{vi}=frac{1}{1-x^v} ]

然后若干个乘起来就是:

[ans=prod_{i=1}^{n}frac{1}{1-x^{v_i}} ]

考虑用(ln)化成为加:

[ln ans=sum_{i=1}^nln frac{1}{1-x^{v_i}} ]

由于:

[ln F(x)=int F'(x)F^{-1}(x)~{ m{d}}x ]

带进去可得:

[ln frac{1}{1-x^{v}}=int frac{vx^{v-1}}{1-x^v}~{ m{d}}x ]

展开再积分:

[ln frac{1}{1-x^{v}}=int sum_{i=1}^{+infty}vx^{vi-1}~{ m{d}}x=sum_{i=1}^{+infty}frac{1}{i}x^{vi} ]

那么这个就可以直接算了,最后(exp)一下就好了,注意处理出这个函数可以用记个桶然后调和级数的小技巧。

时间复杂度(O(nlog n))

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('
');}

#define lf double
#define ll long long 

const int maxn = 8e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353;

int add(int x,int y) {return x+y>mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;}
int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;}

int w[maxn],rw[maxn],pos[maxn],N,bit,f[maxn];
int tmp[10][maxn],n,m,cnt[maxn],inv[maxn],g[maxn],mxn;

int qpow(int a,int x) {
	int res=1;
	for(;x;x>>=1,a=mul(a,a)) if(x&1) res=mul(res,a);
	return res;
}

void ntt_init() {
	w[0]=1,w[1]=qpow(3,(mod-1)/mxn);
	for(int i=2;i<=mxn;i++) w[i]=mul(w[i-1],w[1]);
	rw[0]=1,rw[1]=qpow(w[1],mod-2);
	for(int i=2;i<=mxn;i++) rw[i]=mul(rw[i-1],rw[1]);
}

void ntt_get(int len) {
	for(N=1,bit=0;N<=len;N<<=1,bit++);
	for(int i=0;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));
}

void ntt(int *r,int op) {
	for(int i=0;i<N;i++) if(pos[i]>i) swap(r[i],r[pos[i]]);
	for(int i=1,d=mxn>>1;i<N;i<<=1,d>>=1)
		for(int j=0;j<N;j+=i<<1)
			for(int k=0;k<i;k++) {
				int x=r[j+k],y=mul((op==-1?rw:w)[k*d],r[i+j+k]);
				r[j+k]=add(x,y),r[i+j+k]=del(x,y);
			}
	if(op==-1) {int d=qpow(N,mod-2);for(int i=0;i<N;i++) r[i]=mul(r[i],d);}
}

void poly_inv(int *r,int *t,int len) {
	if(len==1) return t[0]=qpow(r[0],mod-2),void();
	poly_inv(r,t,len>>1);ntt_get(len);
	for(int i=0;i<len>>1;i++) tmp[0][i]=r[i],tmp[1][i]=t[i];
	for(int i=len>>1;i<len;i++) tmp[0][i]=r[i],tmp[1][i]=0;
	for(int i=len;i<N;i++) tmp[0][i]=tmp[1][i]=0;
	ntt(tmp[0],1),ntt(tmp[1],1);
	for(int i=0;i<N;i++) t[i]=del(mul(2,tmp[1][i]),mul(mul(tmp[1][i],tmp[1][i]),tmp[0][i]));
	ntt(t,-1);for(int i=len;i<N;i++) t[i]=0;
}

void poly_der(int *r,int *t,int len) {
	for(int i=1;i<len;i++) t[i-1]=mul(i,r[i]);
	for(int i=len-1;i<len<<1;i++) t[i]=0;
}

void poly_int(int *r,int *t,int len) {
	for(int i=0;i<len;i++) t[i+1]=mul(inv[i+1],r[i]);t[0]=0;
	for(int i=len+1;i<len<<1;i++) t[i]=0;
}

void poly_ln(int *r,int *t,int len) {
	poly_der(r,tmp[2],len);
	poly_inv(r,tmp[3],len);
	ntt_get(len),ntt(tmp[2],1),ntt(tmp[3],1);
	for(int i=0;i<N;i++) tmp[2][i]=mul(tmp[2][i],tmp[3][i]);
	ntt(tmp[2],-1);poly_int(tmp[2],t,len);
	for(int i=0;i<len<<1;i++) tmp[3][0]=0;
}

void poly_exp(int *r,int *t,int len) {
	if(len==1) return t[0]=1,void();
	poly_exp(r,t,len>>1);
	poly_ln(t,tmp[4],len);
	for(int i=0;i<len;i++) tmp[4][i]=del(r[i],tmp[4][i]);tmp[4][0]=add(tmp[4][0],1);
	for(int i=0;i<len;i++) tmp[5][i]=t[i];
	for(int i=len;i<len<<1;i++) tmp[4][i]=tmp[5][i]=0;
	ntt_get(len);ntt(tmp[4],1),ntt(tmp[5],1);
	for(int i=0;i<N;i++) t[i]=mul(tmp[4][i],tmp[5][i]);
	ntt(t,-1);for(int i=len;i<N;i++) t[i]=0;
}

int main() {
	read(n),read(m);
	for(int i=1,x;i<=n;i++) read(x),cnt[x]++;
	inv[0]=inv[1]=1;for(int i=2;i<=m<<2;i++) inv[i]=mul(mod-mod/i,inv[mod%i]);
	for(int i=1;i<=m;i++)
		if(cnt[i]) for(int j=i;j<=m;j+=i) f[j]=add(f[j],mul(cnt[i],inv[j/i]));
	ntt_get(m);mxn=N<<1;ntt_init();poly_exp(f,g,N);
	for(int i=1;i<=m;i++) write(g[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/hbyer/p/10681968.html