Loading

P5488 差分与前缀和

P5488 差分与前缀和

先看前缀和。

首先有一个显然的递推:

\[sum_{k,i}=sum_{k,i-1}+sum_{k-1,i}\\ sum_{0,i}=a_i \]

按照套路考虑 \(a_j\)\(sum_{k,i}\) 的贡献。

看看这个递推,不就是从 \((0,j)\) 走到 \((k,i)\) 这个点的方案数吗??直接 \(\binom{k+i-j}{k}\) 即可。

然后发现挂掉了。。。。。。。

忽然发现 \(sum_{0,i}\) 不能转移到 \(sum_{0,i+1}\) 的!于是少了一步,应该是 \(\binom{k-1+i-j}{k-1}\)

注意这个 \(k\) 太大了,但是是可以直接 \(\bmod 998244353\) 的。然后递推 \(p_i=\binom{k+i}{k}\) 即可。

发现 \(a*p\) 就是答案了。

再考虑差分。

之前见过一点生成函数内容。 \(k\) 阶差分就是乘上 \((1-x)^k\) ,这东西二项式系数就是 \((-1)^i\binom{k}{i}\)

递推预处理 \(p_i=(-1)^i\binom{k}{i}\)\(a*p\) 就是答案了。

const int N=100005;
const int M=N<<2;
#define mod 1004535809
void fmod(int&x){x+=x>>31&mod,x-=mod,x+=x>>31&mod;}
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 exread(){
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(1ll*x*10+ch-'0')%mod,ch=getchar();
	return x;
}

int rev[M],lg,lim;
void init(const int&n){
	for(lg=0,lim=1;lim<=n;lim<<=1,++lg);
	for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
}
void NTT(int*a,int op){
	int g=op?3:qpow(3,mod-2);
	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){
		int wn=qpow(g,(mod-1)/(i<<1));
		for(int j=0;j<lim;j+=i<<1){
			int w0=1;
			for(int k=0;k<i;++k,w0=1ll*w0*wn%mod){
				const int X=a[j+k],Y=1ll*w0*a[i+j+k]%mod;
				fmod(a[j+k]=X+Y),fmod(a[i+j+k]=X-Y+mod);
			}
		}
	}
	if(op)return;int ilim=qpow(lim,mod-2);
	for(int i=0;i<lim;++i)a[i]=1ll*ilim*a[i]%mod;
}

int n,k,t,a[M],f[M];
namespace solve1{
signed main(){
	f[0]=1;for(int i=1;i<n;++i)f[i]=1ll*f[i-1]*(k+i-1)%mod*qpow(i,mod-2)%mod;
	init(n<<1),NTT(a,1),NTT(f,1);
	for(int i=0;i<lim;++i)f[i]=1ll*a[i]*f[i]%mod;
	NTT(f,0);
	for(int i=0;i<n;++i)fmod(f[i]),printf("%d ",f[i]);
	return 0;
}

}
namespace solve2{
signed main(){
	f[0]=1;for(int i=1;i<n;++i)f[i]=-1ll*f[i-1]*(k-i+1)%mod*qpow(i,mod-2)%mod;
	init(n<<1),NTT(a,1),NTT(f,1);
	for(int i=0;i<lim;++i)f[i]=1ll*a[i]*f[i]%mod;
	NTT(f,0);
	for(int i=0;i<n;++i)fmod(f[i]),printf("%d ",f[i]);
	return 0;
}
}
signed main(){
	n=read(),k=exread(),t=read();
	for(int i=0;i<n;++i)a[i]=read();
	if(!t)solve1::main();else solve2::main();
	return 0;
}

大概是我人傻常数大的缘故,不知道为啥别人跑的这么快。。。

posted @ 2020-12-26 08:49  zzctommy  阅读(104)  评论(0编辑  收藏  举报