题解[LuoguP5591]小猪佩奇学数学
前置知识
- 基本数论推式子能力,如分配律结合律等
- 等比数列求和 ∑bi=axi=xb+1−xax−1
- 二项式定理 (a+b)k=∑ki=0(ki)aibk−i 及其特殊形式 (a+1)k=∑ki=1(ki)ai
- 组合恒等式 m(nm)=n(n−1m−1)
- 单位根反演 [d∣n]=1d∑d−1i=0ωnid
题意简述
求
n∑i=0(ni)pi⌊ik⌋
其中 n,p,k 给定,对 998244353 取模。
解题过程
可以发现如果去掉最后的 ⌊ik⌋,那么二项式定理逆用即可,所以我们考虑保留前半部分不动。
要处理 ⌊ik⌋ 类问题,一般依靠其下取整取值数量来做题,但可以发现 f(i)=(ni)pi 不方便前缀和,难以使用这个套路。
所以我们考虑转换,将其改写为 g(x)=∑xi=0[k|i]−1,这里为了方便我们将 0 也算入其中。
那么就可以再使用单位根反演了。
ans=n∑i=0(ni)pi⌊ik⌋=n∑i=0(ni)pii∑j=0[k|j]−n∑i=0(ni)pi=n∑i=0(ni)pii∑j=01kk−1∑l=0ωljk−(p+1)n=1kk−1∑l=0n∑i=0(ni)pii∑j=0(ωlk)j−(p+1)n
这时候可以看到出现了 ∑ij=0(ωlk)j,是一个等比数列求和。
ans=1kk−1∑l=0n∑i=0(ni)pii∑j=0(ωlk)j−(p+1)n=1kk−1∑l=0n∑i=0(ni)pi(ωlk)i+1−1ωlk−1−(p+1)n=1kk−1∑l=0∑ni=0(ni)pi(ωl(i+1)k−1)ωlk−1−(p+1)n=1kk−1∑l=0∑ni=0(ni)piωl(i+1)k−∑ni=0(ni)piωlk−1−(p+1)n=1kk−1∑l=0∑ni=0(ni)piωl(i+1)k−(p+1)nωlk−1−(p+1)n
这下看上去完全推不动了。。。我们再重新审视一下这一个式子,分析一下现在能做到什么复杂度:显然是 O(nk) 过不了,考虑得把内层 O(n) 枚举给省掉,而且其类似于二项式定理的形态也激起了我们化简这一部分的欲望。
所以我们把这一段单独拿出来看一下。
n∑i=0(ni)piωl(i+1)k
如果需要逆用二项式定理,需要去掉最后的 ωl(i+1)k。这个幂的表示看起来不太舒服,换成舒服的形式再放回去试一试:
n∑i=0(ni)piωl(i+1)k=n∑i=0(ni)pi(ωlk)i+1=n∑i=0(ni)pi(ωlk)iωlk=ωlkn∑i=0(ni)pi(ωlk)i
这时可以看到我们将 p 和 ωlk 的指数都化成了相同的 i,那我们可以将二者合并起来看,一起放入二项式定理中。
ans=1kk−1∑l=0ωlk∑ni=0(ni)pi(ωlk)i−(p+1)nωlk−1−(p+1)n=1kk−1∑l=0ωlk∑ni=0(ni)(pωlk)i−(p+1)nωlk−1−(p+1)n=1kk−1∑l=0ωlk(pωlk+1)n−(p+1)nωlk−1−(p+1)n
这时,我们就可以用外层 O(k) 的复杂度枚举,内层 O(log) 级别的复杂度计算快速幂,总复杂度 O(klogn) 解决这个问题。
另外注意到一点:在使用等比数列求和公式时,我们没有去验证 ωlk−1≠0 的前提条件;而当 l=0 时,ωlk=0。
这时我们可以直接特判:
n∑i=0(ni)pii∑j=0ω0k=n∑i=0(ni)pi(i+1)=n∑i=1i(ni)pi+(p+1)n=n∑i=1n(n−1i−1)pi+(p+1)n=n−1∑i=0n(n−1i)pi+1+(p+1)n=npn−1∑i=0(n−1i)pi+(p+1)n=np(p+1)n−1+(p+1)n
注:可以看到从有一处开始将 ∑ 的下界改成了 i=1,这是因为当 i=0 时无贡献。
最后再把整个式子弄出来:
ans=1kk−1∑l=1ωlk(pωlk+1)n−(p+1)nωlk−1−(p+1)n+np(p+1)n−1+(p+1)nk
推式子部分结束。
核心代码
只给出核心代码以供参考,不会实现可以看一看,附有简要注释。数论题还挺好实现罢
typedef long long LL;
const int K=1<<20;
const LL MOD=998244353;
LL n,k,p,ik;
LL omg;
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){
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){
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);
ans=ans*ik%MOD;
ADD(ans,MOD-Pow((p+1)%MOD,n));
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现