LGP7847题解

题意:给定 \(n\),求方程 \(\frac 1 a - \frac 1 b=\frac 1 n\) 的所有解,且解必须满足 \(\gcd(a,b,n)=1\)

以下内容搬运自官方题解:

转化一下:

\[bn=a(b+n) \]

\[a=\frac {bn} {b+n} \]

根据 \(\gcd(a,b,n)=1\),有:

\[\gcd(\frac {bn} {b+n},b,n)=\gcd(\frac {bn} {b+n},\gcd(b,n))=1 \]

接下来设 \(b=x \times \gcd(b,n),n=y \times \gcd(b,n)\),那么一定有 \(\gcd(x,y)=1\)

于是:

\[\gcd(\frac {xy} {x+y} \times \gcd(b,n),\gcd(b,n))=1 \]

\[\gcd(b,n)|(x+y) \]

\(\gcd(xy,x+y)=1,\frac {xy} {x+y} \times \gcd(b,n)\) 是整数,所以有 \((x+y)|\gcd(b,n)\)

于是 \(x+y=\gcd(b,n),b+n=\gcd(b,n) \times (x+y) = \gcd(b,n)^2\)

相当于求方程 \(x+n=\gcd(x,n)\)。(这里的 \(x\) 在上面是 \(b\)

下面为了方便,设 \(\gcd(x,n)=d,c=dk\)

\[d^2=dk+x \]

\[x=d \times (d-k) \]

然后对于 \(d\),枚举可行的 \(k\),最后检查一下是否合法就行。

以上内容搬运自官方题解。

检查是否合法的瓶颈在于,计算 \(\gcd(x,c)=\gcd(d(d-k),c)=\gcd(d(d-k),dk)=d \times \gcd(d-k,k)\)

这里的 \(d-k\)\(k\) 一定有一个数不大于 \(\sqrt n\),所以根据 \(\gcd(a,b)=\gcd(a \bmod b,b)\),可以直接预处理一个 \(\sqrt n \times \sqrt n\) 的表。

再往下推,发现实际上是判断 \(d\times \gcd(d-k,k)=d\),也就是判断 \(d\)\(k\) 是否互质,所以打表可以使用一个 bool 类型的数组来降低常数。

到这里,复杂度已经变成 \(O(n\log n+T)\) 的了。在加强版中,这个做法只跑了 1s,并且卡掉了 \(O(n+T\sqrt n)\) 的暴力,还在原版跑到了300ms

#include<cstdio>
#include<vector>
typedef unsigned uint;
typedef unsigned long long ull;
const uint M=2e6;
uint T,mx,n[100005],ans1[M+5];bool _check[1420][1420];
ull ans[M+5],ans2[M+5];
inline ull min(const ull&a,const ull&b){
	return a>b?b:a;
}
signed main(){
	register uint i,j,x;
	scanf("%u",&T);_check[0][1]=true;
	for(i=1;i<=1415;++i)_check[1][i]=true;
	for(i=2;i<=1415;++i){
		for(x=0,j=i;j<=1415;++j){
			_check[i][j]=_check[x][i];
			if(++x==i)x=0;
		}
	}
	for(i=1;i<=T;++i)scanf("%u",n+i),mx=n[i]>mx?n[i]:mx;
	for(i=1;i<=mx;++i)ans2[i]=0x7f7f7f7f7f7f7f7f;
	for(i=1;i<=mx;++i){
		for(j=1,x=i;j<=i&&x<=mx;++j,x+=i){
			if(_check[i%j][j])ans2[x]=min(ans2[x],1ull*i*(i-j)),++ans1[x];
		}
	}
	for(ans1[i=1]=0;i<=mx;++i)ans1[i]+=ans1[i-1];
	for(i=1;i<=T;++i)printf(n[i]==1?"0\n":"%u %llu\n",ans1[n[i]],ans2[n[i]]);
}
posted @ 2022-01-10 19:14  Prean  阅读(23)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};