题解[LuoguP5591]小猪佩奇学数学

题解[LuoguP5591]小猪佩奇学数学

前置知识

  1. 基本数论推式子能力,如分配律结合律
  2. 等比数列求和 i=abxi=xb+1xax1
  3. 二项式定理 (a+b)k=i=0k(ki)aibki 及其特殊形式 (a+1)k=i=1k(ki)ai
  4. 组合恒等式 m(nm)=n(n1m1)
  5. 单位根反演 [dn]=1di=0d1ωdni

题意简述

i=0n(ni)piik

其中 n,p,k 给定,对 998244353 取模。

解题过程

可以发现如果去掉最后的 ik,那么二项式定理逆用即可,所以我们考虑保留前半部分不动。

要处理 ik 类问题,一般依靠其下取整取值数量来做题,但可以发现 f(i)=(ni)pi 不方便前缀和,难以使用这个套路。

所以我们考虑转换,将其改写为 g(x)=i=0x[k|i]1,这里为了方便我们将 0 也算入其中。

那么就可以再使用单位根反演了。

ans=i=0n(ni)piik=i=0n(ni)pij=0i[k|j]i=0n(ni)pi=i=0n(ni)pij=0i1kl=0k1ωklj(p+1)n=1kl=0k1i=0n(ni)pij=0i(ωkl)j(p+1)n

这时候可以看到出现了 j=0i(ωkl)j,是一个等比数列求和

ans=1kl=0k1i=0n(ni)pij=0i(ωkl)j(p+1)n=1kl=0k1i=0n(ni)pi(ωkl)i+11ωkl1(p+1)n=1kl=0k1i=0n(ni)pi(ωkl(i+1)1)ωkl1(p+1)n=1kl=0k1i=0n(ni)piωkl(i+1)i=0n(ni)piωkl1(p+1)n=1kl=0k1i=0n(ni)piωkl(i+1)(p+1)nωkl1(p+1)n

这下看上去完全推不动了。。。我们再重新审视一下这一个式子,分析一下现在能做到什么复杂度:显然是 O(nk) 过不了,考虑得把内层 O(n) 枚举给省掉,而且其类似于二项式定理的形态也激起了我们化简这一部分的欲望。

所以我们把这一段单独拿出来看一下。

i=0n(ni)piωkl(i+1)

如果需要逆用二项式定理,需要去掉最后的 ωkl(i+1)。这个幂的表示看起来不太舒服,换成舒服的形式再放回去试一试:

i=0n(ni)piωkl(i+1)=i=0n(ni)pi(ωkl)i+1=i=0n(ni)pi(ωkl)iωkl=ωkli=0n(ni)pi(ωkl)i

这时可以看到我们将 pωkl指数都化成了相同的 i,那我们可以将二者合并起来看,一起放入二项式定理中。

ans=1kl=0k1ωkli=0n(ni)pi(ωkl)i(p+1)nωkl1(p+1)n=1kl=0k1ωkli=0n(ni)(pωkl)i(p+1)nωkl1(p+1)n=1kl=0k1ωkl(pωkl+1)n(p+1)nωkl1(p+1)n

这时,我们就可以用外层 O(k) 的复杂度枚举,内层 O(log) 级别的复杂度计算快速幂,总复杂度 O(klogn) 解决这个问题。

另外注意到一点:在使用等比数列求和公式时,我们没有去验证 ωkl10 的前提条件;而当 l=0 时,ωkl=0

这时我们可以直接特判

i=0n(ni)pij=0iωk0=i=0n(ni)pi(i+1)=i=1ni(ni)pi+(p+1)n=i=1nn(n1i1)pi+(p+1)n=i=0n1n(n1i)pi+1+(p+1)n=npi=0n1(n1i)pi+(p+1)n=np(p+1)n1+(p+1)n

注:可以看到从有一处开始将 下界改成了 i=1,这是因为当 i=0无贡献

最后再把整个式子弄出来:

ans=1kl=1k1ωkl(pωkl+1)n(p+1)nωkl1(p+1)n+np(p+1)n1+(p+1)nk

推式子部分结束。

核心代码

只给出核心代码以供参考,不会实现可以看一看,附有简要注释。数论题还挺好实现罢

typedef long long LL;

const int K=1<<20;
const LL MOD=998244353;

LL n,k,p,ik;//ik 是 inv of k
LL omg;//omega
LL ans;

LL Pow(LL x,LL b=MOD-2){
	LL res=1;
	while(b){
		if(b&1)
			res=res*x%MOD;
		x=x*x%MOD;
		b>>=1;
	}
	return res;
}

LL G(LL x){//计算 mod 998244353 意义下的 x 次单位元
	return Pow(3,(MOD-1)/x);
}

int main(){
	n=read(),p=read(),ik=Pow(k=read());
	omg=G(k);
	for(int i=1;i<k;++i){//处理 sigma 内
		int ol=Pow(omg,i);
		ADD(ans,(ol*Pow((p*ol%MOD+1)%MOD,n)%MOD+MOD-Pow((p+1)%MOD,n))%MOD*Pow(ol+MOD-1)%MOD);
	}
	ADD(ans,(n*p%MOD*Pow((p+1)%MOD,n-1)%MOD+Pow((p+1)%MOD,n))%MOD);//处理 l=0
	ans=ans*ik%MOD;
	ADD(ans,MOD-Pow((p+1)%MOD,n));//处理多出来的
	printf("%lld\n",ans);
	return 0;
}
posted @   Diwanul  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示