P3768做题笔记
P3768 做题笔记
神必题给 \(n\) 开到了 \(10^{10}\) ,一个地方没取模直接爆 \(long\,long\) 了,调了一晚上吐了。
一个做法是常规的莫比乌斯反演!最后的做法和下面的做法差不多。
但莫比乌斯反演的式子看起来就很长,而且好像还需要卷一下 \(\varphi\) 一类的东西,推起来非常麻烦,结果也不够精简,我们可以直接用 \(\varphi\) 来表示那个 \(\gcd\)
推式子: \(\sum_{i=1}^n\sum_{j=1}^nij\gcd(i,j)\)
\(=\sum_{i=1}^n\sum_{j=1}^nij\sum_{d|\gcd(i,j)}\varphi(d)\)
\(=\sum_{d=1}^n\varphi(d)d^2(\sum_{i=1}^{n/d}i)^2\)
然后我们就可以非常开心的数论分块,现在问题转化成为如何快速求 \(\sum_{i=l}^r\varphi(i)i^2\)
首先化成前缀和,然后是个积性函数,我们考虑杜教筛。令 \(g(i)=\text{id}^2(i)\varphi(i)\) ,那么我们需要一个 \(h(i)\) 使得可以方便的求 \(g*h\) 的前缀和以及 \(h\) 的前缀和。我们可以考虑如下的引理:
定义点乘为逐项相乘,即 \((f\cdot g)(n)=f(n)\times g(n)\) ,那么设 \(f(i)\) 为完全积性函数(即不要求互质),\(u(i),v(i)\) 为数论函数,那么有
证明:
\(((f\cdot u)*(f\cdot v))(n)=\sum_{d|n}f(d)\times u(d)\times f(\dfrac{n}{d}) \times v(\dfrac{n}{d})=f(n)\times\sum_{d|n}u(d)v(\dfrac{n}{d})=f\cdot(u*v)\)
那么再看回这个题,我们设 \(f=\text{id}^2,u=\varphi,v=\text{1}\) 就有 \(g=f\cdot v=\text{id}^2,g*h=(f\cdot u)*(f\cdot v)=\text{id}^2\cdot(\varphi*1)=\text{id}^3\)
然后我们就可以愉快的杜教筛啦
注意时时取模
\(code\) :
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <map>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 2000010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define ll long long
#define db double
using namespace std;
ll read()
{
ll w=0,flg=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
return w*flg;
}
ll MOD,n,inv2,inv6;
const int yz=2000000;
map<int,ll>mp;
ll phi[MAXN],phisum[MAXN],prnum,prm[MAXN];
bool vis[MAXN];
void sieve()
{
phi[1]=1;
FUP(i,2,yz)
{
if(!vis[i]) prm[++prnum]=i,phi[i]=(ll)(i)*i%MOD*(i-1)%MOD;
FUP(j,1,prnum)
{
if(i*prm[j]>yz) break;
vis[i*prm[j]]=true;
if(i%prm[j]) phi[i*prm[j]]=phi[i]*phi[prm[j]]%MOD;
else
{
phi[i*prm[j]]=phi[i]*prm[j]%MOD*prm[j]%MOD*prm[j]%MOD;
break;
}
}
}
FUP(i,1,yz) phisum[i]=(phisum[i-1]+phi[i]+MOD)%MOD;
}
ll poww(ll a,ll b)
{
ll ans=1,base=a;
while(b)
{
if(b&1) ans=ans*base%MOD;
base=base*base%MOD;
b>>=1;
}
return ans;
}
ll tsum(ll x)
{
x%=MOD;
return x*(x+1)%MOD*(2*x+1)%MOD*inv6%MOD;
}
ll sum3(ll x)
{
x%=MOD;
ll w=x*(x+1)%MOD*inv2%MOD;
return w*w%MOD;
}
ll calc(ll x)
{
if(x<=yz) return phisum[x];
if(mp[x]) return mp[x];
ll ans=sum3(x);
for(ll l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
ans=(ans-(tsum(r)-tsum(l-1)+MOD)%MOD*calc(x/l)%MOD+MOD)%MOD;
}
mp[x]=ans;
return ans;
}
ll ans;
int main(){
MOD=read(),n=read(),inv2=poww((ll)2,MOD-2),inv6=poww((ll)6,MOD-2);
//printf("%lld\n",2*inv2%MOD);
sieve();
for(ll l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ll w1=(calc(r)-calc(l-1)+MOD)%MOD;
ll w2=sum3(n/l);
//printf("%lld %lld %lld\n",ans,w1,w2);
ans=(ans+w1*w2%MOD)%MOD;
}
printf("%lld\n",ans);
return 0;
}