您的位置:首页 > 其它

【欧拉】 UVA 11426 GCD - Extreme (II)

2015-07-31 10:25 489 查看
这次不挂题目地址。。。因为UVa的感觉。。。好吧我还是贴题目吧。

Problem J

GCD Extreme (II)

Input:
Standard Input
Output: Standard Output

Given the value of N, you will have to find the value of G. The definition of G is given below:



Here GCD(i,j) means the greatest common divisor of integer i and integer j.

For those who have trouble understanding summation notation, the meaning of G is given in the following code:

G=0;

for(i=1;i<N;i++)

for(j=i+1;j<=N;j++)

{

G+=gcd(i,j);

}

/*Here gcd() is a function that finds the greatest common divisor of the two input numbers*/

Input
The input file contains at most 100 lines of inputs. Each line contains an integer N (1<N<4000001). The meaning of N is given in the problem statement. Input is terminated by a line containing a single zero.

Output

For each line of input produce one line of output. This line contains the value of G for the corresponding N. The value of G will fit in a 64-bit signed integer.

Sample Input Output for Sample Input

10

100

200000

0

67

13015

143295493160

Problemsetter: Shahriar Manzoor

Special Thanks: SyedMonowarHossain

题目要求的是范围内的所有gcd( i , j )( j > i ) 和。。。我们的第一反应自然是去求 gcd( i , n) 然后预处理成o(1)输出。。。

然而这时候发现数字太大不能直接求。

看题解的时候给的公式是这样的

for(int i=1;i<=4000000;i++)

{

for(int j=2*i;j<=4000000;j+=i)

{

ans[j]+=oura[j/i]*i;

}

ans[i]+=ans[i-1];

}

然而不理解,之后去问了人之后得到了这个的证明方法

-------------------------------------------分割线-----------------------------------------------------

首先我们把gcd打成表。

| 1 2 3 4 5 6 7 8

-----+-------------------------------------------------------

1 | 1 1 1 1 1 1 1 1

2 | 1 2 1
2 1 2 1 2

3 | 1 1 3 1 1 3 1
1

4 | 1 2 1 4 1
2 1 4

5 | 1 1 1 1 5 1 1 1

6 | 1 2 3 2 1 6 1
2

7 | 1 1 1 1 1 1 7 1

8 | 1 2 1 4 1 2 1
8

显然,黄底的部分就是我们找的答案

这时候我们把2的倍数的取出来看看的话

| 1 2 3 4 5 6 7 8

-----+-------------------------------------------------------

1 | 1 1 1 1 1 1 1 1

2 | 1 2
1 2 1
2 1 2

3 | 1 1 3 1 1 3 1 1

4 | 1 2 1 4
1 2 1
4

5 | 1 1 1 1 5 1 1 1

6 | 1 2 3 2
1 6 1 2

7 | 1 1 1 1 1 1 7 1

8 | 1 2 1 4
1 2 1
8

你会发现如果再对每项除以2就是和刚刚一样的图了

此时的所有2变成1,我们用欧拉函数便可很快的将它们取出来

同理可推广到所有数字,因此有了之前的公式。。。

-------------------------------------------分割线-----------------------------------------------------

代码其实可以不用了吧。。。毕竟刚刚讲的挺详细了(是这样吗?)

而且我的代码风格感觉并不是很好。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long

using namespace std;

int oura[4000010];
int prime[300000],cont;
long long ans[4000010];

void init()
{
cont=0;
for(int i=2;i<=4000000;i++)
{
if(!oura[i])
{
prime[cont++]+=i;
oura[i]=i-1;
}
for(int j=0;j<cont;j++)
{
if(prime[j]>4000000/i) break;
if(i%prime[j]!=0)
oura[prime[j]*i]=oura[i]*(prime[j]-1);
else
{
oura[prime[j]*i]=oura[i]*prime[j];
break;
}
}
}

ans[0]=0;
for(int i=1;i<=4000000;i++)
{
for(int j=2*i;j<=4000000;j+=i)
{
ans[j]+=oura[j/i]*i;
}
ans[i]+=ans[i-1];
}
}

int main()
{
init();
int n;
while(~scanf("%d",&n) && n)
{
printf("%lld\n",ans
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: