【题意】给定n,求Σφ(i),n<=10^10。
【算法】杜教筛
【题解】
定义$s(n)=sum_{i=1}^{n}varphi(i)$
杜教筛$sum_{i=1}^{n}(varphi *I)(i)=sum_{i=1}^{n}sum_{d|i}varphi(d)=sum_{i=1}^{n}sum_{d=1}^{frac{n}{i}}varphi(d)$
根据$id=varphi*I$,$sum_{i=1}^{n}(varphi*I)(i)=frac{i(i+1)}{2}$
所以$s(n)=frac{i(i+1)}{2}-sum_{i=2}^{n}s(frac{n}{i})$
然后递归进行即可,预处理前$n^{frac{2}{3}}$项,则复杂度为O(n^(2/3))。
本质上是对于id=φ*I,其中I和id的前缀和都可以直接计算,所以可以用杜教筛处理φ的前缀和。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int sq=100000,pre=5000000,MOD=1e9+7,inv=(MOD+1)/2; int a[100010],phi[pre+5],prime[pre],tot; ll N; bool vis[pre+5]; int solve(ll n){ if(n<=pre)return phi[n]; if(~a[N/n])return a[N/n]; int ans=n%MOD*((n+1)%MOD)%MOD*inv%MOD;// ll pos=2; for(ll i=pos;i<=n;i=pos+1){ pos=n/(n/i); ans=(ans-1ll*(pos-i+1)%MOD*solve(n/i)%MOD+MOD)%MOD; } return a[N/n]=ans; } int main(){ scanf("%lld",&N); phi[1]=1; for(int i=2;i<=pre;i++){ if(!vis[i]){phi[prime[++tot]=i]=i-1;} for(int j=1;j<=tot&&i*prime[j]<=pre;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;} phi[i*prime[j]]=phi[i]*(prime[j]-1); } phi[i]=(phi[i]+phi[i-1])%MOD; } memset(a,-1,sizeof(a)); printf("%d",solve(N)); return 0; }