F - 小清新数论
杜教筛能的,跑了1423ms,对上面公式中欧拉函数前n项和,欧拉函数前n项和进行杜教筛,然后套一个分块求解
#include<stdio.h>
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define INV2 499122177
using namespace std;
typedef long long ll;
const int N=1e7+20;
const int mod=998244353;
bool vis[N];
int mu[N],sum1[N];
long long phi[N],sum2[N];
int cnt,prim[N];
int e,e1;
tr1::unordered_map<long long,long long>w,w1; //哈希 w用来求phi前缀和 w1用来求miu前缀和
void get(int maxn)
{
phi[1]=mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
{
prim[++cnt]=i;
mu[i]=-1;phi[i]=i-1;
}
for(int j=1;j<=cnt&&prim[j]*i<=maxn;j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
else mu[i*prim[j]]=-mu[i],phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
for(int i=1;i<=maxn;i++)sum1[i]=sum1[i-1]+mu[i],sum2[i]=(sum2[i-1]+phi[i])%mod; //打一个maxn的phi前缀和表 和miu前缀和表
}
int djsmu(long long x) // 求miu前缀和
{
if(x<=10000000)return sum1[x];
if(w[x])return w[x];
int ans=1;
for(long long l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
ans-=(r-l+1ll)*djsmu(x/l);
}
return w[x]=ans;
}
long long djsphi(long long x) //求phi 前缀和
{
if(x<=10000000)return sum2[x];
if(w1[x])return w1[x];
long long ans=x%mod*(x+1)%mod*INV2%mod;
for(long long l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
ans=(ans-(r-l+1)%mod*djsphi(x/l)+mod)%mod;
}
while(ans<0)ans+=mod;
return w1[x]=ans%mod;
}
int main(){
get(10000000);
ll n,r;
scanf("%lld",&n);
ll ans=0,res;
for(ll l=1;l<=n;l=r+1){
r=n/(n/l);
res=(ll)(djsmu(r)-djsmu(l-1)+mod)%mod*((djsphi(n/l)%mod*(ll)2%mod-1+mod)%mod)%mod;
ans=(ans+res+mod)%mod;
}
printf("%lld\n",ans);
return 0;
}