GCD 极值(gcd) hgoi0501 题解
题目描述
输入
- 输入包括 T 组测试数据,每组数据只包含一个整数 N,含义如题所述。注意,测试数
据中 T 的值未知。
测试数据的最后一行是个 0,这一行无需处理。
输出
- 每组测试数据输出一行,为 G 的值,其结果不会超过 64 位带符号整数。
样例
数据规模
- 对于 30% 的数据,2 N 1 000; 1 T 100
对于 60% 的数据,2 N 4 000 000; 1 T 100
对于另外的 40% 的数据,2 N 200 000; 1 T 20 000
题目解析
- 一道非常玄妙的数学题。
- 用到了欧拉函数的特性并使用递推和直接计算两种方法应对不同的数据规模。
- 具体待补全
先附上AC程序
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
#define LIM 4000001
void finit(){
freopen("gcd.in","r",stdin);
freopen("gcd.out","w",stdout);
}
ll g[LIM],flag[LIM],phi[LIM],sumphi[LIM];
ll prime[300000];
int prf=0;
int main(){
finit();
for (int i=2;i<=LIM;i++){
if (!flag[i]) prime[prf++]=flag[i]=i;
for (int j=0;j<prf&&i*prime[j]<=LIM;j++){
flag[i*prime[j]]=prime[j];
if (i%prime[j]==0)
break;
}
}
phi[1]=1;
for (int i=2;i<LIM;i++){
phi[i]=phi[i/flag[i]];
if ((i/flag[i])%flag[i]==0)
phi[i]*=flag[i];
else
phi[i]*=(flag[i]-1);
sumphi[i]=sumphi[i-1]+phi[i];
}
ll n;
ll maxx=1,sum=0;
while (cin>>n){
if (!n) break;
if (n<=200000){
if (n>maxx){
for (int i=maxx+1;i<=n;i++){
g[i]=g[i-1]+phi[i];
for (int j=2;j<=sqrt(i);j++)
if (i%j==0)
if (i/j!=j)
g[i]+=phi[i/j]*j+phi[j]*(i/j);
else
g[i]+=phi[i/j]*j;
}
maxx=n;
}
cout<<g[n]<<'\n';
}else{
sum=sumphi[n];
for(int i=2;i<=n/2;i++){
sum+=sumphi[n/i]*i;
}
cout<<sum<<'\n';
}
}
return 0;
}