Luogu3768简单的数学题

时间:2023-12-19 18:24:26

题目描述

Luogu3768简单的数学题

题解

我们在一通化简上面的式子之后得到了这么个东西。

Luogu3768简单的数学题

前面的可以除法分块做,后面的∑T2∑dµ(T/d)是积性函数,可以线性筛。

然后这个数据范围好像不太支持线性筛,所以考虑杜教筛。

后面那个东西是个id*µ,恰好等于φ

所以我们求得东西就变成了i2φ

由于φ*I=id。所以我们令g(i)=i2,f(x)=i2φ,f*g=i3

于是这道题就做完了。

附:1^2+2^2+3^2+...+n^2=n*(n+1)*(2*n+1)/6,1^3+2^3+...+n^3=(1+2+3+..+n)^2

代码

#include<iostream>
#include<cstdio>
#include<map>
#define N 5000009
using namespace std;
typedef long long ll;
map<ll,ll>mp;
const int maxn=;
ll mod,ans,inv2,inv6,k,phi[N],n;
int prime[N];
bool vis[N];
inline ll rd(){
ll x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline ll power(ll x,ll y){
ll ans=;
while(y){if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;}
return ans;
}
inline void prework(){
ll k;
phi[]=;
for(int i=;i<=maxn;++i){
if(!vis[i]){prime[++prime[]]=i;phi[i]=i-;}
for(int j=;j<=prime[]&&(k=i*prime[j])<=maxn;++j){
vis[i*prime[j]]=;
if(i%prime[j]==){phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
for(int i=;i<=maxn;++i)phi[i]=(phi[i]*i%mod*i%mod+phi[i-])%mod;
}
inline ll sum(ll x){return x%mod*(x+)%mod*inv2%mod;}
inline ll pf(ll x){return x%mod*x%mod;}
inline ll pfsum(ll x){return x%mod*(x+)%mod*(*x%mod+)%mod*inv6%mod;}
ll get_phi(ll n){
if(n<=maxn)return phi[n];
if(mp.find(n)!=mp.end())return mp[n];
ll ans=pf(sum(n));ll r;
for(ll l=;l<=n;l=r+){
r=n/(n/l);
ll x=((pfsum(r)-pfsum(l-))%mod+mod)%mod;
ans=(ans-x*get_phi(n/l)%mod+mod)%mod;
}
return mp[n]=ans;
}
int main(){
mod=rd();n=rd();
inv2=power(,mod-);inv6=power(,mod-);
prework();
ll l,r;
for(l=;l<=n;l=r+){
r=n/(n/l);
ans+=pf(sum(n/l))*(get_phi(r)-get_phi(l-))%mod;
ans=(ans%mod+mod)%mod;
}
cout<<ans;
return ;
}