真实奥数题
题目大意:给你正整数k$,r$。问你存在多少对$(x,y)$,满足$x<y$且$x^2+y^2=kz^2$,并将所有符合条件的数对输出。
数据范围:$r≤1e9$,$k={1,2,3}$。
我们先考虑$k=1$的情况,显然就是一个求勾股数对数的问。有一种经典的枚举所有$x^2+y^2=z^2$且$(x,y,z)=1$的勾股数对数的式子:
$\begin{cases} x=2nm\\ y=n^2-m^2 \\ z=n^2+m^2 \end{cases}$
证明的话,展开下式子算算就好
我们只需要暴力枚举r的因数进行计算就可以了,时间复杂度$O(r^{\frac{1.066}{\ln\ln\ n}+0.5})$(这个式子是抄来的,证明本蒟蒻不懂,反正是能过的qwq)。
考虑$k=2$的情况,我们参考处理$k=1$的情况,列一组式子,可以枚举所有$x^2+y^2=2z^2$且$(x,y,z)=1$的式子:
$\begin{cases} x=n-m\\ y=n+m \\ z=\sqrt{n^2+m^2} \end{cases}$
证明同上
我们不难发现,这时候求解的关键变为了求$z^2=n^2+m^2$的对数(并将所有方案打出),这不就是第一问吗$qwq$。
我们只需要求出所有的$(n,m)$数对后,简单转化一波就可以了。
考虑k=3的情况,抱歉这个是无解的qwq
#include<bits/stdc++.h>
#define L long long
#define M 10000005
using namespace std; pair<L,L> p[M]; int cnt=; int solve(L z,L bei){
int res=;
for(L n=;n*n<=z;n++){
L m=sqrt(z-n*n),x=,y=;
if(m*m+n*n!=z) continue;
x=*n*m;
y=n*n-m*m;
if(x==y) continue;
if(x>y) swap(x,y);
if(x<=) continue;
p[++cnt]=make_pair(x*bei,y*bei);
res++;
}
return res;
} int main(){
int cas; cin>>cas;
while(cas--){
L k,z,ans=; cin>>k>>z; cnt=;
if(k==) {printf("0\n"); continue;}
for(L i=;i*i<=z;i++) if(z%i==){
ans+=solve(i,z/i);
if(i*i!=z) ans+=solve(z/i,i);
}
sort(p+,p+cnt+);
cnt=unique(p+,p+cnt+)-p-;
if(k==){
for(int i=;i<=cnt;i++){
p[i]=make_pair(p[i].second-p[i].first,p[i].second+p[i].first);
}
sort(p+,p+cnt+);
cnt=unique(p+,p+cnt+)-p-;
}
printf("%d\n",cnt);
for(int i=;i<=cnt;i++) printf("%d %d\n",p[i].first,p[i].second); }
}