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;
    }
    
  • 相关阅读:
    Notes about "Exploring Expect"
    Reuse Sonar Checkstyle Violation Report for Custom Data Analysis
    Eclipse带参数调试的方法
    MIT Scheme Development on Ubuntu
    Manage Historical Snapshots in Sonarqube
    U盘自动弹出脚本
    hg的常用配置
    Java程序员的推荐阅读书籍
    使用shared memory 计算矩阵乘法 (其实并没有加速多少)
    CUDA 笔记
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10272268.html
Copyright © 2011-2022 走看看