51nod 1188 最大公约数之和 V2
原创
©著作权归作者所有:来自51CTO博客作者mb5f5b1df7f1e34的原创作品,请联系作者获取转载授权,否则将追究法律责任
1188 最大公约数之和 V2
- 2.0 秒
-
- 262,144.0 KB
-
- 160 分
-
- 6级题
给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和。
相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数):
G=0;
for(i=1;i<N;i++)
for(j=i+1;j<=N;j++)
{
G+=gcd(i,j);
}
收起
输入
第1行:1个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行一个数N。(2 <= N <= 5000000)
输出
共T行,输出最大公约数之和。
输入样例
3
10
100
200000
输出样例
67
13015
143295493160
分析:
简化版
51nod 1040 最大公约数之和 数学+欧拉函数
我们知道每一个与i最大公约数肯定是n的因子,我们枚举n的因子x,然后求满足gcd(n,k)=x的个数即可,相当于求gcd(n/x,k/x)=1(k/x<n/k),即求有多少数与n/x互质,这就需要欧拉函数了。
即变为:i|n代表n%i==0
这题可以化为:
注意第三个等式的j变为i的因子。
到了第三个等式,我们发现题意变为枚举i(i属于[2,n]),然后枚举i的因子j(除了本身)求出答案和,但换个角度我们枚举每一个因子j,放大几倍当作i来使用。
这题需要离线,不离线的话会超时
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
const ll N=5000055;
int prime[N],mark[N];//prime是素数数组,mark为标记不是素数的数组
ll tot,phi[N];//phi为φ(),tot为1~i现求出的素数个数
void getphi(int N)
{
phi[1]=1;//φ(1)=1
for(int i=2; i<=N; i++) //从2枚举到N
{
//cout<<i<<" "<<tot<<endl;
if(!mark[i]) //如果是素数
{
prime[++tot]=i;//那么进素数数组,指针加1
phi[i]=i-1;//根据性质1所得
}
for(int j=1; j<=tot; j++) //从现求出素数枚举
{
if(i*prime[j]>N)
break;//如果超出了所求范围就没有意义了
mark[i*prime[j]]=1;//标记i*prime[j]不是素数
if(i%prime[j]==0) //应用性质2
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*phi[prime[j]];//应用性质3
}
}
}
ll ans[N],a[50005],sum[N];
int main()
{
getphi(N-1);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(ll i=1; i<=N-1; i++)
{
for(ll j=2; i*j<=N-1; j++)
{
ans[i*j]+=phi[j]*i;
}
}
for(ll i=1;i<=N;i++)
{
sum[i]=ans[i]+sum[i-1];
}
for(int i=1;i<=n;i++)
printf("%lld\n",sum[a[i]]);
return 0;
}