【LOJ6482】LJJ 爱数数 数论

题目大意

  给你 (n),求

[sum_{a=1}^nsum_{b=1}^nsum_{c=1}^n[frac{1}{a}+frac{1}{b}=frac{1}{c}][gcd(a,b,c)=1]\ ]

  (nleq {10}^{12})

题解

[egin{align} &sum_{a=1}^nsum_{b=1}^nsum_{c=1}^n[frac{1}{a}+frac{1}{b}=frac{1}{c}][gcd(a,b,c)=1]\ =&sum_{a=1}^nsum_{b=1}^nsum_{c=1}^n[c(a+b)=ab][gcd(a,b,c)=1]\ =&sum_{a=1}^nsum_{b=1}^n[(a+b)mid ab][gcd(a,b,c)=1]\ end{align} ]

  通过打表可以发现,一对数 (a,b(aleq b)) 满足条件的充要条件是 (bleq n)(frac{a}{gcd(a,b)}+frac{b}{gcd(a,b)}=gcd(a,b))

  证明:

  若 (gcd(a,b)=1),则 (gcd(a+b,ab)=1)

  记 (g=gcd(a,b),a=ga',b=gb'),则

[a+b=g(a'+b')\ ab=g^2a'b'\ frac{ab}{a+b}=frac{g^2a'b'}{g(a'+b')}=frac{ga'b'}{a'+b'}\ ]

  所以 ((a'+b')mid g)

  若 (a'+b' eq g),则 (gcd(a,b,c)=frac{g}{a'+b'}),所以 (a'+b'=g) 所以 (a=a'(a'+b'),b=b'(a'+b'),c=a'b')

解法一

  记 (x=a',y=b')

[egin{align} ans&=sum_{x=1}^nsum_{y=x}^n[xy+y^2leq n]gcd(x,y)=1\ &=sum_{d=1}^sqrt{n}mu(d)sum_{x=1}sum_{y=x}[xy+y^2leq frac{n}{d^2}]\ &=sum_{d=1}^sqrt{n}mu(d)sum_{y=1}minleft(leftlfloorfrac{leftlfloorfrac{n}{d^2} ight floor-y^2}{y} ight floor,y ight) end{align} ]

  时间复杂度:(O(sqrt nlog n))

解法二

  (a+b=g^2)

  枚举 (g),那么 (gcd(g,a')=1)

  当 (g) 比较小的时候 ((1leq gleq sqrt n))(a')(varphi(g)) 种取值,可以直接筛

  当 (g) 比较大的时候 ((sqrt n<g<sqrt{2n}))

[sum_{i=1}^frac{n}{g}[gcd(g,i)=1]\ =sum_{dmid g}mu(d)lfloorfrac{n}{gd} floor ]

  可以暴力枚举因子。

  时间复杂度:(O(sqrt nlog n))

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<functional>
#include<cmath>
#include<vector>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}
int check(int x,int y)
{
	return x*y%(x+y)==0;
}
const int N=1000010;
int b[N];
int pri[N];
int miu[N];
int cnt;
int main()
{
//	open("loj6482");
	ll n;
	scanf("%lld",&n);
	miu[1]=1;
	for(int i=2;i<=1000000;i++)
	{
		if(!b[i])
		{
			pri[++cnt]=i;
			miu[i]=-1;
		}
		for(int j=1;j<=cnt&&i*pri[j]<=1000000;j++)
		{
			b[i*pri[j]]=1;
			if(i%pri[j]==0)
				break;
			miu[i*pri[j]]=-miu[i];
		}
	}
	ll ans=0;
	for(int i=1;(ll)i*i<=n;i++)
		if(miu[i])
		{
			ll s=0;
			for(int j=1;;j++)
			{
				int z=min((n/i/i-(ll)j*j)/j,(ll)j);
				if(z<=0)
					break;
				s+=z;
			}
			ans+=miu[i]*s;
		}
	ans=ans*2-1;
	printf("%lld
",ans);
//	int ans=0;
//	for(int i=1;i<=n;i++)
//		for(int j=1;j<=n;j++)
//			if(gcd(i,j)==1&&i*(i+j)<=n&&j*(i+j)<=n)
//				ans++;
//	printf("%d
",ans);
//	return 0;
//	int n=1000;
//	for(int i=1;i<=n;i++)
//		for(int j=i;j<=n;j++)
//			if(gcd(i,j)==1&&check(i*(i+j),j*(i+j))&&gcd(gcd(i*(i+j),j*(i+j)),i*j)==1)
//				if(j*(i+j)<=n)
//					printf("%d %d %d
",i*(i+j),j*(i+j),i*j);
//	return 0;
//	for(int i=1;i<=n;i++)
//		for(int j=i;j<=n;j++)
//			if(i*j%(i+j)==0)
//			{
//				int z=i*j/(i+j);
//				if(gcd(gcd(i,j),z)==1)
//					printf("%d %d %d %d %d %d
",i,j,z,gcd(i,j),i/gcd(i,j),j/gcd(i,j));
//			}
//	return 0;
}
原文地址:https://www.cnblogs.com/ywwyww/p/9832481.html