uva-11426 GCD - Extreme (II) (欧拉函数和gcd的关系)

题目链接: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

扫描二维码关注公众号,回复: 2649421 查看本文章

因为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;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81532756
今日推荐