三角形

Portal --> who knows qwq

Description

  给你\(n\)条边,长度都不超过\(A\),问有多少种选边的方案满足这三条边能构成一个直角三角形

  数据范围:\(1<=n<=10^6,1<=A<=10^5\)
  

Solution

  我的小学数学可能白学了qwq

  

  直觉是。。直接枚举勾股数但是这个东西要怎么枚举呢。。。

  有两种方法:

  第一种是对于所有的满足\(gcd(x,y,z)=1\)\(x^2+y^2=z^2\)的三元组,它的解可以写成:

\[\begin{cases} x=t(a^2-b^2)\\ y=2tab\\ z=t(a^2+b^2) \end{cases} \]

  所以我们枚举这个\(a\)\(b\)就好了,然后倍数跳上去。。

​   

​  第二种方法是如果说你不知道上面的这个结论,那么可以直接简单处理一下式子:

\[\begin{aligned} x^2+y^2&=z^2\\ x^2&=z^2-y^2\\ &=(z-y)(z+y) \end{aligned} \]

  所以我们可以枚举\(x\),然后枚举\(x^2\)的因数就好了qwq

  

​  mark:主要是mark一下上面那个勾股数的结论qwq

  

​  第一种方法的代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e6+10,MOD=998244353;
int a[N];
int cnt[N];
int n,m,ans;
int mul(int x,int y){return 1LL*x*y%MOD;}
int plu(int x,int y){return (1LL*x+y)%MOD;}
int gcd(int x,int y){return y?gcd(y,x%y):x;}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	ll x,y,z;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) scanf("%lld",&x),++cnt[x];
	for (int i=1;i*i<=m;++i){
		for (int j=1;j<=i;++j){
			x=1LL*i*i-1LL*j*j;
			y=1LL*2*i*j;
			z=1LL*i*i+1LL*j*j;
			if (z>m) continue;
			if (gcd(x,gcd(y,z))>1) continue;
			for (int x1=x,y1=y,z1=z;z1<=m;x1+=x,y1+=y,z1+=z)
				ans=plu(ans,mul(cnt[x1],mul(cnt[y1],cnt[z1])));
		}
	}
	printf("%d\n",ans);
}
posted @ 2018-10-29 16:38  yoyoball  阅读(229)  评论(1编辑  收藏  举报