zoukankan      html  css  js  c++  java
  • P7102 [w3R1] 算

    P7102 [w3R1] 算

    [s(n)=sum_{i=1}^{n}p(i)sum_{d|gcd(i,n)}mu(d)\ =sum_{d|n}mu(d)sum_{i=1}^{frac{n}{d}}p(id)\ =sum_{d|n}mu(d)sum_{i=1}^{frac{n}{d}}sum_{j=0}^{m-1}a_j(id)^{j}\ =sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jd^jsum_{i=1}^{frac{n}{d}}i^j ]

    后面有一个自然数幂和的东西,考虑直接伯努利数求通项,这是一个 (j+1) 次多项式。设这个多项式为

    [S_k(n)=sumlimits_{i=0}^{n}i^k=k!sumlimits_{i=1}^{k+1}dfrac{B_i}{(k+1-i)!}n^{k+1-i}+n^k ]

    如果你不了解怎么搞这个通项,可以看 多项式笔记(二) 。(这里的 (B_i) 是伯努利数 ( m EGF)([x^i]) 系数,也就是除以了阶乘的)

    不过这里注意一件事情,伯努利数的求和上界是 (n-1) ,所以用伯努利数算 (B) 的时候,最后要单独加 (n^k) 。以及伯努利数默认 (0^0=1) ,要减掉 。这个一般弱于前面的那个和式,单独讨论一下就能解决,留到最后再说。

    暴力带进去。

    [=sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jd^jsum_{i=1}^{frac{n}{t}}i^j\ =sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jd^jj!sum_{i=1}^{j+1}dfrac{B_i}{(j+1-i)!}(dfrac{n}{d})^{j+1-i}\ =sum_{j=0}^{m-1}a_jj!sum_{i=0}^{j}dfrac{B_i}{(j+1-i)!}n^{j+1-i}sum_{d|n}mu(d)d^{i-1}\ ]

    后面那个是积性函数,看几眼就感觉很可做。

    考虑把 (n) 质因数分解了,对于每一个 (p^k) 算答案,然后乘起来。

    观察到 (mu(p^k)) 当且仅当在 (k=0)(k=1) 时有值。

    所以

    [sum_{d|p^k}mu(d)d^{i-1}=1-p*p^{i-1}=1-p^i ]

    (f(k,n)=sum_{d|n}mu(d)d^k) ,那么显然有 (f(k,n^c)=f(k,n)) ,因为一旦存在 (p) 这个因子就必然只会产生 (1-p^k) 的贡献,与因子数量无关。

    Pollard-Rho预处理质因数,可以 (O(log n)) 左右算出来,不是瓶颈就是了。

    那么可以直接预处理所有 (A_i=f(i-1,c))

    [=sum_{j=0}^{m-1}a_jj!sum_{i=0}^{j}n^{j+1-i}dfrac{B_{i}}{(j+1-i)!}A_i\ =sum_{j=0}^{m-1}a_jj!sum_{i=0}^{j}n^{i+1}dfrac{B_{j-i+1}}{(i+1)!}A_{j-i+1}\ =sum_{i=0}^{m-1}n^{i+1}dfrac{1}{(i+1)!}sum_{j=i}^{m-1}a_{j}j!A_{j-i}B_{j-i} ]

    发现这个就是一个与 (n) 有关的多项式,系数差卷积一下就可以出来。然后我们需要求出连续的 (c^i) 的点值,就是CZT变换板子,不会可以看 多项式笔记(一)

    然后来讨论伯努利数边界的问题:我们会多算所有 (0^0) ,要减掉;会漏算所有 ((dfrac{n}{t})^j) ,要加上。

    拉一个比较原始的式子下来:

    [sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jd^jsum_{i=1}^{frac{n}{d}}i^j\ ]

    多算 (0^0) 当且仅当 (j=0) ,这时候贡献是 (sum_{d|n}mu(d)a_0=a_0 imes[n=1]) ,也就是说只有在 (n=1) 的时候会多算 (a_0)

    这个好办,直接判一下 (c=1) 的情况,输出 (t)(p(1)) 即可。

    少算 ((dfrac{n}{d})^j) 稍微棘手一些

    [sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jd^j(dfrac{n}{d})^j\ =sum_{d|n}mu(d)sum_{j=0}^{m-1}a_jn^j\ =sum_{j=0}^{m-1}a_jn^jsum_{d|n}mu(d)\ =sum_{j=0}^{m-1}a_jn^j[n=1]\ ]

    发现还是在 (n=1) 的时候会出事,然而已经判掉了所以啥事没有。

    好难码啊,边界乱七八糟的/kk。

    不过出题人貌似不想给完整代码(详见commd_block洛谷题解评论),所以我也不给完整代码了/cy。但是删去部分都是很简单的部分,只防xxs,并且加了详细注释,如果你有做这题的水平必然看得懂。

    LL mul(LL x,LL y,LL mod){
    	LL res=x*y-(long long)((long double)x/mod*y+0.5)*mod;
    	return res<0?res+mod:res;
    }
    LL gcd(LL x,LL y){
    	while(y){LL t=x%y;x=y,y=t;}
    	return x;
    }
    LL qpow(LL n,LL k,LL mod){
    	LL res=1;for(;k;k>>=1,n=mul(n,n,mod))if(k&1)res=mul(res,n,mod);
    	return res;
    }
    
    namespace MR{
    int testp[8]={2,3,5,7,11,19,61,233};
    bool mr(LL x,LL p){
    	if(x%p==0||qpow(p,x-1,x)!=1)return 0;
    	LL k=x-1;
    	while(!(k&1)){
    		LL t=qpow(p,k>>=1,x);
    		if(t!=x-1&&t!=1)return 0;
    		if(t==x-1)break;
    	}
    	return 1;
    }
    bool test(LL x){
    	for(int i=0;i<8;++i){
    		if(x==testp[i])return 1;
    		if(!mr(x,testp[i]))return 0;
    	}
    	return 1;
    }
    }
    
    namespace PR{
    int tot;
    LL d[150];
    mt19937_64 rnd(673);
    LL pr(LL x,LL c){
    	if(x==4)return 2;
    	static LL s[150],v0,v1,g;
    	static int len;
    	len=0,v0=c,v1=mul(v0,v0,x)+c,g=1;
    	while(1){
    		s[++len]=v1-v0,g=mul(g,v1-v0,x);
    		if(len==127){if(gcd(g,x)>1)break;len=0;}
    		v0=mul(v0,v0,x)+c,v1=mul(v1,v1,x)+c,v1=mul(v1,v1,x)+c;
    	}
    	for(int i=1;i<=len;++i)if((g=gcd(s[i],x))>1)return g;
    	return x;
    }
    void solve(LL x){
    	if(x==1)return;
    	if(MR::test(x))return d[++tot]=x,void();
    	LL y=x;while(y==x)y=pr(x,rnd()%(x-1)+1);
    	solve(x/y),solve(y);
    }
    void work(LL x){tot=0,solve(x),sort(d+1,d+tot+1);}
    
    }
    
    const int N=200005;
    const int M=N*3*2;
    #define mod 998244353
    
    namespace math{
    int inv[N],fac[N],ifc[N];
    inline int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
    inline int comb(int n,int m){return n<m?0:1ll*fac[n]*ifc[m]%mod*ifc[n-m]%mod;}
    inline void fmod(int&x){x-=mod,x+=x>>31&mod;}
    void initmath(const int&n=N-1){
    	fac[0]=1;for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%mod;
    	ifc[n]=qpow(fac[n],mod-2);for(int i=n-1;i>=0;--i)ifc[i]=1ll*ifc[i+1]*(i+1)%mod;
    	inv[1]=1;for(int i=2;i<=n;++i)inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    }
    }
    using namespace math;
    
    namespace poly{
    
    int rev[M],rt[M],lim;
    void initpoly(const int&n){
    	static int lg;
    	for(lg=0,lim=1;lim<n;++lg,lim<<=1);
    	for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
    	for(int i=1;i<lim;i<<=1){
    		int w=qpow(3,(mod-1)/(i<<1));
    		rt[i]=1;
    		for(int j=1;j<i;++j)rt[i+j]=1ll*rt[i+j-1]*w%mod;
    	}
    }
    void NTT(int*a,int op){
    	if(!op)reverse(a+1,a+lim);
    	for(int i=0;i<lim;++i)
    		if(i>rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<lim;i<<=1){
    		for(int j=0;j<lim;j+=i<<1){
    			for(int k=0;k<i;++k){
    				const int t=1ll*rt[i+k]*a[i+j+k]%mod;
    				fmod(a[i+j+k]=a[j+k]+mod-t),fmod(a[j+k]+=t);
    			}
    		}
    	}
    	if(!op)for(int i=0,iv=qpow(lim,mod-2);i<lim;++i)a[i]=1ll*a[i]*iv%mod;
    }
    #define clr(a,n) memset(a,0,sizeof(int)*(n))
    #define cpy(a,b,n) memcpy(a,b,sizeof(int)*(n))
    void poly_mul(int*f,int*g,int*ans,int n,int m){//这是卷积,f[0,1,...,n-1]*g[0,1,...,m-1]->ans[0,1,...,n+m-2]
    }
    void poly_inv(int*g,int*f,int n){//这是多项式求逆,f[0,1,...,n-1]的逆元->g[0,1,...,n-1]
    }
    void bernoulli(int*g,int n){
    	static int A[M];
    	for(int i=0;i<n;++i)A[i]=ifc[i+1];
    	clr(g,n),poly_inv(g,A,n);
    }
    void CZT(int*g,int*f,int m,int n,int c){//给定n-1次多项式f,求f(c^{0->m-1})
    	static int pw[N<<1],ipw[N<<1],ivc,A[M],B[M];
    	pw[0]=pw[1]=ipw[0]=ipw[1]=1,ivc=qpow(c,mod-2);
    	for(int i=2;i<n+m;++i)pw[i]=1ll*pw[i-1]*c%mod,ipw[i]=1ll*ipw[i-1]*ivc%mod;
    	for(int i=2;i<n+m;++i)pw[i]=1ll*pw[i-1]*pw[i]%mod,ipw[i]=1ll*ipw[i-1]*ipw[i]%mod;
    	for(int i=0;i<n;++i)A[i]=1ll*f[i]*ipw[i]%mod;
    	for(int i=0;i<n+m;++i)B[i]=pw[i];
    	reverse(A,A+n),poly_mul(A,B,A,n,n+m);
    	for(int i=0;i<m;++i)g[i]=1ll*ipw[i]*A[i+n-1]%mod;
    }
    
    }
    
    using PR::d;
    using PR::tot;
    int m,t,a[N],A[M],B[M],tem[N],num,pri[N];
    LL c;
    signed main(){
    	initmath();
    	scanf("%d%lld%d",&m,&c,&t),++t;
    	for(int i=0;i<m;++i)a[i]=read();
    	if(c==1){
    		static LL sum;
    		sum=0;for(int i=0;i<m;++i)sum+=a[i];
    		int s=sum%mod;
    		for(int i=1;i<t;++i)printf("%d ",s);
    		return 0;
    	}
    	PR::work(c);
    	for(int l=1,r=0;l<=tot;l=r+1){
    		while(r<tot&&d[r+1]==d[l])++r;
    		pri[++num]=d[l]%mod;
    	}
    	A[0]=1;
    	for(int i=1;i<=num;++i)A[0]=1ll*A[0]*(mod+1-(tem[i]=qpow(pri[i],mod-2)))%mod;
    	for(int i=1;i<m;++i){
    		A[i]=1;
    		for(int j=1;j<=num;++j)A[i]=1ll*A[i]*(mod+1-(tem[j]=1ll*tem[j]*pri[j]%mod))%mod;
    	}
    	poly::bernoulli(B,m);
    	for(int i=0;i<m;++i)A[i]=1ll*A[i]*B[i]%mod;
    	for(int i=0;i<m;++i)B[i]=1ll*a[i]*fac[i]%mod;
    	reverse(A,A+m),poly::poly_mul(A,B,B,m,m);
    	for(int i=0;i<m;++i)A[i+1]=1ll*ifc[i+1]*B[i+m-1]%mod;
    	A[0]=0,clr(B,t),poly::CZT(B,A,t,m+1,c%mod);
    	for(int i=1;i<t;++i)printf("%d
    ",B[i]);
    	return 0;
    }
    
  • 相关阅读:
    Ubuntu Linux Matlab 安装 中文乱码 桌面启动器 Could not find the main class: java/splash.png. 终端terminal 直接运行 matlab
    Ubuntu Linux 官网 u盘安装 u盘系统 图文教程
    从google map google earth获得大图 方法总结
    论文查重网址
    [ZZ] Computer Science Conference Rankings
    Ubuntu linux 信使 iptux Window 飞鸽 ipmsg 飞秋 feiq 文件传输
    Ubuntu Linux Matlab mex
    Ubuntu Dell OptiPlex 990 Intel Gigabit CT Desktop Adapter网卡驱动安装
    C++的File类文件操作
    GIS软件比较
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14301079.html
Copyright © 2011-2022 走看看