zoukankan      html  css  js  c++  java
  • [洛谷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;
    }
    
  • 相关阅读:
    HDU 6071
    HDU 6073
    HDU 2124 Repair the Wall(贪心)
    HDU 2037 今年暑假不AC(贪心)
    HDU 1257 最少拦截系统(贪心)
    HDU 1789 Doing Homework again(贪心)
    HDU 1009 FatMouse' Trade(贪心)
    HDU 2216 Game III(BFS)
    HDU 1509 Windows Message Queue(队列)
    HDU 1081 To The Max(动态规划)
  • 原文地址:https://www.cnblogs.com/hbyer/p/10681968.html
Copyright © 2011-2022 走看看