• 51nod乘积之和


    题目链接

    戳我

    题意简述

    你有长为(n)的序列和(Q)个询问,每次询问一个(k),求用(k)个数组成的不同方案的乘积的和。

    sol

    显然要预处理一波。

    考虑分治,左右两边都求出来后,怎么合并。

    (A[i])为整体用(i)个数的乘积和,(B[i])为左边用(i)个数的乘积和,(C[i])为右边用(i)个数的乘积和。

    则很显然有(A[i]=sum_{j=0}^i B[j]C[i-j])

    这是一个卷积然后NTT就好了,然而怎么模数是1e5+3,那就双模数NTT吧,虽然常数巨大,FFT也可以,写的好的话常数优秀5~6倍。总复杂度(O(nlog^2n))

    疯狂压行ing~

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define gt getchar()
    #define ll long long
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    inline int in(){int k=0;char ch=gt;while(ch<'-')ch=gt;while(ch>'-')k=k*10+ch-'0',ch=gt;return k;}
    const int N=3e5+5,g=3,p[]={998244353,1004535809},inv[]={669690699,332747959};const ll MOD=1ll*p[0]*p[1];
    int rev[N],v1[N],v2[N],v3[N],v4[N];ll f[50][N];
    inline int MO(const int &a,int now){return a>=p[now]?a-p[now]:a;}
    inline int ksm(int a,int k,int now){int r=1;while(k){if(k&1)r=1ll*r*a%p[now];a=1ll*a*a%p[now],k>>=1;}return r;}
    inline ll  mul(ll  a,ll  k        ){ll  r=0;while(k){if(k&1)r=(r + a)%  MOD ;a=(a + a)%  MOD ,k>>=1;}return r;}
    void get_rev(int len,int qwq){rev[0]=0;for(int i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<qwq-1);}
    void ntt(int *a,int len,int opt,int now)
    {
    #define YL p[now]
    	for(int i=0;i<len;++i)if(i<rev[i])std::swap(a[i],a[rev[i]]);
    	for(int st=2,m=1;st<=len;st<<=1,m<<=1)
    	{
    		int wn=ksm(g,opt==1?(YL-1)/st:YL-1-(YL-1)/st,now);
    		for(int *pp=a;pp!=a+len;pp+=st)
    			for(int k=0,wnk=1;k<m;++k,wnk=1ll*wnk*wn%YL)
    			{
    				int t=1ll*wnk*pp[k+m]%YL;
    				pp[k+m]=MO(pp[k]-t+YL,now);
    				pp[k]=MO(pp[k]+t,now);
    			}
    	}
    	if(opt==1)return;int inv=ksm(len,YL-2,now);
    	for(int i=0;i<len;++i)a[i]=1ll*a[i]*inv%YL;
    #undef YL
    }
    const int YL=1e5+3;
    int a[N];
    void get_mul(int *a,int *b,int len,int now)
    {
    	ntt(a,len, 1,now);ntt(b,len, 1,now);
    	for(int i=0;i<len;++i)a[i]=1ll*a[i]*b[i]%p[now];
    	ntt(a,len,-1,now);
    }
    void cdq_fft(int l,int r,int x)
    {
    	for(int i=0;i<=r-l+1;++i)f[x][i]=0;
    	if(l==r){f[x][0]=1,f[x][1]=a[l];return;}
    	int mid=l+r>>1;cdq_fft(l,mid,x+1);
    	for(int i=0;i<=r-l+1;++i)f[x][i]=f[x+1][i];cdq_fft(mid+1,r,x+1);
    	int m=r-l+1,qwq=0,len=1;
    	while(len<=m)len<<=1,++qwq;get_rev(len,qwq);
    	for(int i=r-mid+1;i<len;++i)f[x+1][i]=0;
    	for(int i=mid-l+2;i<len;++i)f[ x ][i]=0;
    	for(int i=0;i<len;++i)v1[i]=v2[i]=f[x][i],v3[i]=v4[i]=f[x+1][i];
    	get_mul(v1,v3,len,0);get_mul(v2,v4,len,1);
    	for(int i=0;i<=m;++i)
    	{
    		f[x][i]=mul(1ll*v1[i]*p[1]%MOD,inv[1]);
    		ll tttt=mul(1ll*v2[i]*p[0]%MOD,inv[0]);
    		f[x][i]=(f[x][i]+tttt)%MOD;
    		f[x][i]=(f[x][i]+YL)%YL;
    	}
    }
    int main()
    {
    	int n=in(),q=in();for(int i=1;i<=n;++i)a[i]=in()%YL;
    	cdq_fft(1,n,0);while(q--)printf("%lld
    ",f[0][in()]);
    	return 0;
    }
    
    
  • 相关阅读:
    解决loss值不下降问题(转)
    c++ int转string
    图的遍历
    JavaScript类型和语法
    cesium清除选定事件
    cesium中divPoint展示数据
    cesium安装及第一个示例
    2、cesium页面小控件的隐藏
    4、cesium场景出图,打印图件
    5、cesium点击面高亮事件
  • 原文地址:https://www.cnblogs.com/cx233666/p/9708024.html
Copyright © 2020-2023  润新知