zoukankan      html  css  js  c++  java
  • HDU 5829 Rikka with Subset(NTT)

    题意

    给定 (n) 个数 (a_1,a_2,cdots a_n),对于每个 (Kin[1,n]) ,求出 (n) 个数的每个子集的前 (K) 大数的和,输出每个值,对 (998244353) 取模。

    (1leq n leq 10^5)

    思路

    (K)(k) 时的答案为 (ans_k)

    [ans_k=sum_{i=1}^na_i2^{n-i}sum_{j=0}^{k-1}{i-1choose j} ]

    (j) 为在 (a_i) 的左边选了多少个数。定义当(i<j)(displaystyle{ichoose j}=0) ,即当 (n<0)(displaystyle{1over n!}=0)

    有两个(sum) ,导致难以化简,但是我们发现差分后只有一个 (sum)

    (d_k=ans_k-ans_{k-1}) ,则有

    [d_k=sum_{i=1}^na_i2^{n-i}{i-1choose k-1}\ d_k=(k-1)!sum_{i=1}^na_i2^{n-i}(i-1)!cdot{1over{(i-k)!}} ]

    (i+k) 替换 (k) ,并化成卷积形式

    [d_{i+k}=(i+k-1)!a_i2^{n-i}(i-1)!cdot{1over{(-k)!}} ]

    其中 (iin[1,n],i+kin[1,n],kin[1-n,n-1])

    (displaystyle A_i=a_i2^{n-i}(i-1)!,B_k={1over{(-k)!}})

    (d_{i+k}=(i+k-1)A_iB_k)

    处理出 (A,B) 两多项式,进行卷积求解即可。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    typedef long long ll;
    using namespace std;
    const int P=998244353,g=3;
    const int N=1<<17|5;
    namespace Maths
    {
    	ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    	void exgcd(ll a,ll b,ll &x,ll &y)
    	{
    		if(!b){x=1,y=0;return;}
    		exgcd(b,a%b,y,x),y-=a/b*x;
    	}
    	ll Pow(ll a,ll p,ll P)
    	{
    		ll res=1;
    		for(;p>0;p>>=1,(a*=a)%=P)if(p&1)(res*=a)%=P;
    		return res;
    	}
    	ll inv(ll a,ll P){ll x,y;exgcd(a,P,x,y);return (x%P+P)%P;}
    };
    using namespace Maths;
    namespace _NTT
    {
    	const int g=3,P=998244353;
    	int A[N<<1],B[N<<1];
    	int w[N<<1],r[N<<1];
    	void NTT(int *a,int op,int n)
    	{
    		FOR(i,0,n-1)if(i<r[i])swap(a[i],a[r[i]]);
    		for(int i=2;i<=n;i<<=1)
    			for(int j=0;j<n;j+=i)
    				for(int k=0;k<i/2;k++)
    				{
    					int u=a[j+k],t=(ll)w[op==1?n/i*k:n-n/i*k]*a[j+k+i/2]%P;
    					a[j+k]=(u+t)%P;
    					a[j+k+i/2]=(u-t)%P;
    				}
    	}
    	void multiply(int *a,int *b,int *c,int n1,int n2)
    	{
    		int n=1;
    		while(n<n1+n2-1)n<<=1;
    		FOR(i,0,n1-1)A[i]=a[i];
    		FOR(i,0,n2-1)B[i]=b[i];
    		FOR(i,n1,n-1)A[i]=0;
    		FOR(i,n2,n-1)B[i]=0;
    		FOR(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)*(n>>1));
    		w[0]=1,w[1]=Pow(g,(P-1)/n,P);
    		FOR(i,2,n)w[i]=(ll)w[i-1]*w[1]%P;
    		
    		NTT(A,1,n),NTT(B,1,n);
    		FOR(i,0,n-1)A[i]=(ll)A[i]*B[i]%P;
    		NTT(A,-1,n);
    		int I=inv(n,P);
    		FOR(i,0,n1+n2-2)c[i]=((ll)A[i]*I%P+P)%P;
    	}
    };
    int A[N],B[N],C[N<<2];
    int fac[N],c[N],S;
    int n,m;
    
    int main()
    {
    	fac[0]=1;FOR(i,1,N-1)fac[i]=(ll)fac[i-1]*i%P;
    	while(~scanf("%d",&n))
    	{
    		FOR(i,0,n)scanf("%d",&c[i]);
    		scanf("%d",&m);
    		S=0;
    		while(m--)
    		{
    			int x;
    			scanf("%d",&x);
    			S-=x;
    			if(S<0)S+=P;
    		}
    		FOR(i,0,n)A[i]=(ll)c[i]*fac[i]%P;
    		FOR(i,-n,0)B[i+n]=Pow(S,-i,P)*inv(fac[-i],P)%P;
    		_NTT::multiply(A,B,C,n+1,n+1);
    		FOR(i,0,n)printf("%lld ",(C[i+n]*inv(fac[i],P)%P+P)%P);
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    刷题的 vscodeleetcode
    一个简单的小程序演示Unity的三种依赖注入方式
    WCF服务端运行时架构体系详解[上篇]
    通过WCF扩展实现消息压缩
    通过“四大行为”对WCF的扩展[原理篇]
    [WCF权限控制]利用WCF自定义授权模式提供当前Principal[原理篇]
    [WCF权限控制]ASP.NET Roles授权[下篇]
    [WCF权限控制]通过扩展自行实现服务授权[提供源码下载]
    通过自定义ServiceHost实现对WCF的扩展[实例篇]
    [WCF权限控制]WCF自定义授权体系详解[实例篇]
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10272268.html
Copyright © 2011-2022 走看看