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

    前言

    经典题。

    题目

    洛谷

    讲解

    首先对 \(998244353\) 条件反射,然后发现答案是 \(\prod \frac{1}{1-x^{v_{i}}}\)

    但是直接做是 \(O(nm\log_2m)\) 的,甚至跑不过背包,接下来就是NB优化。

    我们暂且先不考虑倒数,令 \(F(x)=1-x^{V}\),幂次的累乘可以自然想到取对数后转为累加。

    \(\ln(F(x))=G(x)\)

    \[\begin{aligned}(\ln(F(x)))'&=G'(x)\\\frac{F'(x)}{F(x)}&=G'(x)\\-\frac{Vx^{V-1}}{1-x^{V}}&=G'(x)\\-\sum_{i=0}Vx^{V-1+Vi}&=G'(x)\\-\sum_{i=0}\frac{Vx^{V+V_{i}}}{V+Vi}&=G(x)\\-\sum_{i=0}\frac{x^{V+Vi}}{1+i}&=G(x)\\-\sum_{i=1}\frac{x^{Vi}}{i}&=G(x)\\\end{aligned} \]

    看看我们得到了什么!\(\ln(1-x^V)=-\sum_{i=1}\frac{x^{Vi}}{i}\)

    显然后面那个东西的和可以直接在 \(O(m\ln m)\) 的时间里把所有系数都预处理出来,然后做个exp,最后求逆就是答案。

    时间复杂度 \(O(m\ln m)\)

    代码

    人傻常数大
    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 1 << 18 | 5;
    const int MOD = 998244353;
    const int PHI = 998244352;
    const int GINV = 332748118,G = 3;
    int n,m;
    int a[MAXN],b[MAXN],ans[MAXN],cnt[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int inv[MAXN];
    void init()
    {
    	inv[0] = inv[1] = 1;
    	for(int i = 2;i < MAXN;++ i) inv[i] = 1ll * inv[MOD%i] * (MOD - MOD/i) % MOD;
    }
    int qpow(int x,int y)
    {
    	int ret = 1;
    	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
    	return ret;
    }
    int rev[MAXN],len;
    int pre(int L)
    {
    	int l = -1; len = 1;
    	while(len < (L<<1)) len <<= 1,++l;
    	for(int i = 1;i < len;++ i) rev[i] = (rev[i>>1] >> 1) | ((i & 1) << l);
    	return len;
    }
    int Ad(int x){if(x >= MOD) x -= MOD;if(x < 0) x += MOD;return x;}
    void NTT(int *a,int f)
    {
    	for(int i = 0;i < len;++ i) if(i < rev[i]) swap(a[i],a[rev[i]]);
    	for(int i = 1;i < len;i <<= 1)
    	{
    		int w = qpow(f > 0 ? G : GINV,PHI / (i<<1));
    		for(int j = 0,p = i << 1;j < len;j += p)
    			for(int k = 0,mi = 1;k < i;++ k,mi = 1ll * mi * w % MOD)
    			{
    				int X = a[j+k],Y = 1ll * mi * a[i+j+k] % MOD;
    				a[j+k] = Ad(X+Y);
    				a[i+j+k] = Ad(X-Y+MOD);
    			}
    	}
    	if(f == -1) for(int i = 0,in = qpow(len,MOD-2);i < len;++ i) a[i] = 1ll * a[i] * in % MOD;
    }
    int tmp1[MAXN],tmp2[MAXN];
    void polymul(int *a,int lena,int *b,int lenb,int *ret)//巨慢
    {
    	pre(Max(lena,lenb));
    	for(int i = 0;i < len;++ i) if(i < lena) tmp1[i] = a[i]; else tmp1[i] = 0;
    	for(int i = 0;i < len;++ i) if(i < lenb) tmp2[i] = b[i]; else tmp2[i] = 0;
    	NTT(tmp1,1); NTT(tmp2,1);
    	for(int i = 0;i < len;++ i) ret[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    	NTT(ret,-1);
    }
    void polyinv(int *a,int *ret,int N)//还行 
    {
    	if(N == 1){ret[0] = qpow(a[0],MOD-2);return;}
    	polyinv(a,ret,(N+1)>>1); pre(N);
    	for(int i = 0;i < len;++ i) if(i < N) tmp1[i] = a[i]; else tmp1[i] = 0;
    	NTT(tmp1,1); NTT(ret,1);
    	for(int i = 0;i < len;++ i) ret[i] = (2ll * ret[i] - 1ll * tmp1[i] * ret[i] % MOD * ret[i] % MOD + MOD) % MOD;
    	NTT(ret,-1); for(int i = N;i < len;++ i) ret[i] = 0;
    }
    int ad[MAXN],tmp3[MAXN];
    void polyln(int *a,int *ret,int N)//还行 
    {
    	pre(N); for(int i = 0;i < len;++ i) ad[i] = tmp3[i] = 0;
    	for(int i = 1;i < N;++ i) ad[i-1] = 1ll * i * a[i] % MOD;//导 
    	polyinv(a,tmp3,N);
    	polymul(ad,N,tmp3,N,ret);
    	for(int i = N-1;i >= 1;-- i) ret[i] = 1ll * ret[i-1] * inv[i] % MOD;//积 
    //	for(int i = N;i < len;++ i) ret[i] = 0;
    	ret[0] = 0;
    }
    int tmp4[MAXN],tmp5[MAXN];
    void polyexp(int *a,int *ret,int N)//还行 
    {
    	if(N == 1) {ret[0] = 1;return;}//a[0] = 0;
    	polyexp(a,ret,(N+1) >> 1); 
    	polyln(ret,tmp4,N); --tmp4[0]; //pre(N);
    	for(int i = 0;i < len;++ i) if(i < N) tmp4[i] = (MOD-tmp4[i]+a[i]) % MOD; else tmp4[i] = 0;
    	polymul(ret,N,tmp4,N,ret);
    //	for(int i = N;i < len;++ i) ret[i] = 0;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	init();
    	n = Read(); m = Read();
    	for(int i = 1;i <= n;++ i) ++cnt[Read()];
    	for(int i = 1;i <= m;++ i)
    		if(cnt[i])
    			for(int j = i,k = 1;j <= m;j += i,++ k)
    				a[j] = (a[j] - 1ll * cnt[i] * inv[k] % MOD + MOD) % MOD;
    	polyexp(a,b,m+1);
    	polyinv(b,ans,m+1);
    	for(int i = 1;i <= m;++ i) Put(ans[i],'\n');
    	return 0;
    }
    
  • 相关阅读:
    详解Paint的setPathEffect(PathEffect effect)
    详解Paint的setMaskFilter(MaskFilter maskfilter)
    用TextPaint来绘制文字
    详解Paint的setXfermode(Xfermode xfermode)
    详解Paint的setColorFilter(ColorFilter filter)
    ASP.NET Core 高性能开发最佳实践
    疫苗,为啥还要等这么久?
    物联网行业的基本系统架构
    超级强大的学习方法--费曼技巧
    衡水中学学霸李江珊,高考英语149分,从不刷题的她如何做到的
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15777894.html
Copyright © 2011-2022 走看看