1. 程式人生 > >BZOJ4804 尤拉心算(莫比烏斯反演+尤拉函式+線性篩)

BZOJ4804 尤拉心算(莫比烏斯反演+尤拉函式+線性篩)

  一通套路後得Σφ(d)μ(D/d)⌊n/D⌋2。顯然整除分塊,問題在於怎麼快速計算φ和μ的狄利克雷卷積。積性函式的卷積還是積性函式,那麼線性篩即可。因為μ(pc)=0 (c>=2),所以f(pc)還是比較好算的,討論一波即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define
N 10000001 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,phi[N],mobius[N],prime[N],cnt; ll f[N]; bool flag[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj4804.in","r",stdin); freopen("bzoj4804.out","w",stdout); const char LL[]="%I64d\n
"; #else const char LL[]="%lld\n"; #endif T=read(); flag[1]=1;mobius[1]=1;phi[1]=1;f[1]=1; for (int i=1;i<N;i++) { if (!flag[i]) prime[++cnt]=i,phi[i]=i-1,mobius[i]=-1,f[i]=i-2; for (int j=1;j<=cnt&&prime[j]*i<N;j++) { flag[prime[j]*i]=1; if (i%prime[j]==0) { phi[prime[j]*i]=phi[i]*prime[j]; if ((i/prime[j])%prime[j]) f[prime[j]*i]=f[i/prime[j]]*(1ll*prime[j]*prime[j]-2*prime[j]+1); else f[prime[j]*i]=f[i]*prime[j]; break; } mobius[prime[j]*i]=-mobius[i]; phi[prime[j]*i]=phi[i]*(prime[j]-1); f[prime[j]*i]=f[i]*(prime[j]-2); } } for (int i=1;i<N;i++) f[i]+=f[i-1]; while (T--) { n=read();ll ans=0; for (int i=1;i<=n;i++) { int t=n/(n/i); ans+=(f[t]-f[i-1])*(n/i)*(n/i); i=t; } printf(LL,ans); } return 0; }