GCD SUM
题目描述
for i=1 to n
for j=1 to n
sum+=gcd(i,j)
给出n求sum. gcd(x,y)表示x,y的最大公约数.
输入输出格式
输入格式:
n
输出格式:
sum
输入输出样例
说明
数据范围 30% n<=3000 60% 7000<=n<=7100 100% n<=100000
分析:
无聊的出题人出的无聊的数学题。
这里博主用了一种比较暴力的思想,直接枚举以$1 hicksim n$为$GCD$的数对个数,然后累加得到答案就行了,然后就不难得到公式:
$ans=sum^n_{i=1}((sum^{lfloor n/i floor}_{j=1} phi(i)-1)*i+i)$
Code:
//It is made by HolseLee on 27th Oct 2018 //Luogu.org P2398 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const ll N=1e5+7; ll n,phi[N],sum[N],q[N],top,ans; bool vis[N]; void ready() { phi[1]=1; for(ll i=2; i<=n; ++i) { if( !vis[i] ) phi[q[++top]=i]=i-1; for(ll j=1,k; j<=top && (k=q[j]*i)<=n; ++j) { vis[k]=1; if( i%q[j] ) phi[k]=phi[i]*(q[j]-1); else { phi[k]=phi[i]*q[j]; break; } } } for(ll i=2; i<=n; ++i) sum[i]=sum[i-1]+phi[i]; } int main() { scanf("%lld",&n); ready(); ll now; for(ll i=1; i<=n; ++i) { now=n/i; //cout<<sum[now]<<' '<<i<<' '; ans+=sum[now]*i*2+i; } printf("%lld ",ans); return 0; }