题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2421
题目大意:给一个数n,输出sigma(gcd(i,j))1<=i<=j,i<=j<=n,
n因为是4*10^6+1暴力必定超时;
根据gcd(a,b)=x 得gcd(a/x,b/x)=1,即得a/x与b/x互素,因此,求出b/x得欧拉值,表示有oula(b/x)个a/x。
例:n=6
gcd(x,b)=1说明a,b为互质的,就是oula(b)得出的结果中的一个
下式中,oula(6)=2,意思为有两个gcd(x,6)=1的x;所以他们的gcd之和为1*2=2
同理:遍历1~6,找到所有的欧拉值,对应的就是有多少个对应的数字了
oula(6/2)=oula(3)=2 ; 有两个gcd(x,6)=2的x,所以他们的gcd之和为2*2=4
oula(6/3)=oula(2)=1; 有一个gcd(x,6)=3的x,所以他们的gcd之和为3*1=3
因为6/4与6/5不为整数,因此没有对应的欧拉值
oula(6/6)=oula(1)=1; 有一个gcd(x,6)=6的x,所以他们的gcd之和为6*1=6
gcd(1,6); = 1 第一个oula(6/1)=1的(与6互素的数)
gcd(2,6); = 2 第一个oula(6/2)=1的(与3互素的数)就是第一个gcd(x,6)=2的数
gcd(3,6); = 3 第一个oula(6/3)=1的(与2互素的数)就是第一个gcd(x,6)=3的数
gcd(4,6); = 2 第一个oula(6/2)=1的(与3互素的数)就是第二个gcd(x,6)=2的数
gcd(5,6); = 1 第二个oula(6/1)=1的(与6互素的数)
gcd(6,6); = 6 第一个oula(6/6)=1的(1的欧拉值) 就是第一个gcd(x,6)=6的数
所以,有第一个循环遍历范围内的1~n,第二个循环遍历可以整除的所有数字,我们直接乘上去,必定整除
因此可以根据打出的oula值表进行求和
ac:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 1000000007
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
ll ans[4000100],oula[4000100];
//void euler()
//{
// int ans=n;
// for(int i=2;i*i<=n;++i)
// {
// if(n%i==0)
// {
// ans=ans-ans/i;
// while(n%i==0)
// n=n/i;
// }
// }
// if(n>1)
// ans=ans-ans/i;
//}
void intt()
{
clean(ans,0);
clean(oula,0);
oula[1]=1;
for(int i=2;i<4000100;++i)
{
if(oula[i]==0)
{
for(int j=1;j*i<4000100;++j)
{
if(oula[j*i]==0)
oula[j*i]=i*j;
oula[i*j]=oula[i*j]-oula[i*j]/i;
}
}
//对于一个oula[i]的值,每乘以一个j,代表 gcd(x,i*j)=j 中 有oula[i] 个 x
// 遍历完所有的oula[i]
for(int j=1;j*i<4000100;++j)
ans[i*j]=ans[i*j]+oula[i]*j;
}
for(int i=1;i<4000100;++i)
ans[i]=ans[i-1]+ans[i];
}
int main()
{
intt();
ll n;
while(cin>>n)
{
if(n==0)
break;
cout<<ans[n]<<endl;
}
}