P4917 天守阁的地板

这是 luogu P4917 的题解,只是为了方便放学习笔记里就把这篇搬过来了。QWQ

正文

首先分析题意,明显可以发现的是,如果想使最后摆成一个正方形,且用的地板最小,那这个正方形的边长就是 lcm(a,b),那地板的数量就是 lcm(a,b)a×lcm(a,b)b

现在开始推柿子。

求:

i=1nj=1nlcm2(i,j)ijmod19260817

首先知道 lcm(a,b)=abgcd(a,b)

i=1nj=1nijgcd2(i,j)mod19260817

i=1nj=1nij(i=1nj=1ngcd(i,j))2mod19260817

先看分子。

i=1nj=1nij

i=1ninn!

(n!)n(n!)n

(n!)2n

因为这是分子,所以计算时直接对 19260817 取模就行了。

再看分母。

i=1nj=1ngcd(i,j)

(那个平方等最后直接乘就行了)

i=1nj=1nd=1nd[gcd(i,j)=d]

显然,对于任一个 ijgcd(i,j) 有唯一确定的值,且 [...] 里东西如果为假就为 0,所以就用的是求和。

d=1ni=1nj=1nd[gcd(id,jd)=1][d|i][d|j]

d=1ni=1ndj=1ndd[gcd(i,j)=1]

为方便,设 m=nd

d=1ndi=1mj=1m[gcd(i,j)=1]

只看指数。

i=1mj=1m[gcd(i,j)]

可以发现这和仪仗队里的柿子一模一样,但我还是小推一下。

2×i=1mj=1i[gcd(i,j)=1]1

2×i=1mφ(i)1

再看:

d2×i=1mφ(i)1mod19260817

知道 ap11(modp)p 为质数且 gcd(a,p)=1)(费马小定理)。

相当于当我们求 2×i=1nφ(i)1 时,我们可以将其对 19260816192608171)取余,这样我们提前求的时候就不怕爆 long long 了。QWQ

所以我们要求的就变成了:

d=1ndf(nd)mod19260817

f(x)=2×i=1xφ(i)1

如果暴力求,时间复杂度会爆炸,所以考虑优化。显然可以用数论分块优化,对于枚举的 nd,它的贡献为 (r!(l1)!)f(nd),所以可以再套一个快速幂即可。

再往回看,现在整体的柿子就变成了:

(n!)2n(d=1ndf(nd))2mod19260817

所以分别求出分子和分母,记得将分母变成平方并转成逆元即可。

代码

点击查看代码
#include<bits/stdc++.h> #define XD 114514 #define MAXN 1000010 #define ll long long using namespace std; const int mod=19260817; const int mod2=19260816;//mod-1 int t,n,ans,ans1,ans2; int fac[MAXN],phi[MAXN],num[MAXN]; //num 为欧拉函数前缀和,fac 为阶乘 vector<int> prm; bool vis[MAXN]; void sieve(){ phi[1]=num[1]=1; for(int i=2;i<=1e6;i++){ if(!vis[i]) prm.push_back(i),phi[i]=i-1; num[i]=(num[i-1]+phi[i])%mod2; for(auto j:prm){ if(i*j>1e6) break; vis[i*j]=true; if(i%j==0){ phi[i*j]=phi[i]*j;break; } phi[i*j]=phi[i]*phi[j]; } } fac[0]=1; for(int i=1;i<=1e6;i++) fac[i]=1ll*fac[i-1]*i%mod; } int power(int x,int y){//快速幂 int nem=1; while(y){ if(y&1) nem=1ll*nem*x%mod; x=1ll*x*x%mod;y>>=1; } return nem; } int inv(int x){//求逆元 if(x==0 or x==1) return 1; return power(x,mod-2)%mod; } void calc(){//数论分块 int r;ans2=1; for(int l=1;l<=n;l=r+1){ r=n/(n/l); ans2=1ll*ans2*power(1ll*fac[r]*inv(fac[l-1])%mod,(2ll*num[n/l]-1)%mod2)%mod; } } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); sieve(); cin>>t; while(t--){ cin>>n; ans1=power(fac[n],2*n); calc(); ans2=1ll*ans2*ans2%mod; ans=1ll*ans1*inv(ans2)%mod; cout<<ans<<"\n"; } return 0; }

__EOF__

本文作者wdgm4
本文链接https://www.cnblogs.com/wdgm4/p/17765357.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   wdgm4  阅读(37)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示