题目大意
给出直角三角形的周长 n n n,求出有多少个不同的直角三角形满足 a + b + c = n a+b+c=n a+b+c=n,且三边长均为整数。
思路一
关于本原直角三角形可以戳这里,不多解释了直接上代码(顺便吐槽一波这题内存怎么卡这么紧)
//
// Created by Happig on 2020/10/18
//
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define ENDL "\n"
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 1e7 + 10;
int gcd[3510][3510];
int prime[maxn / 2], num[1005], pfac[1005], C[maxn];
vector<int> fac;
bitset<maxn> vis;
int cnt, tot;
void init() {
for (int i = 1; i <= 3500; i++) {
for (int j = 1; j <= 3500; j++) {
if (!gcd[i][j]) {
for (int k = 1; k * i <= 3500 && k * j <= 3500; k++)
gcd[k * i][k * j] = k;
}
}
}
int up = sqrt(maxn), xx = 0;
for (int m = 2; m < up; m++) {
for (int n = 1; n < m; n++) {
if (gcd[m][n] > 1) continue;
int sym = (n ^ m) & 1, cc = 2 * m * m + 2 * n * m;
if (sym && cc < maxn) {
C[cc]++;
}
}
}
}
void euler() {
cnt = 0;
vis.reset();
for (int i = 2; i < maxn; i++) {
if (!vis[i]) prime[++cnt] = i;
for (int j = 1; j <= cnt && 1LL * i * prime[j] < maxn; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
void divide(int n) {
tot = 0;
int up = sqrt(n + 0.5);
for (int i = 1; prime[i] <= up; i++) {
if (n % prime[i] == 0) {
pfac[++tot] = prime[i], num[tot] = 0;
while (n % prime[i] == 0) {
num[tot]++;
n /= prime[i];
}
}
}
if (n > 1) {
pfac[++tot] = n;
num[tot] = 1;
}
}
void dfs(int d, ll cur = 1) {
if (d == tot + 1) {
fac.push_back(cur);
return;
}
for (int i = 0; i <= num[d]; i++) {
dfs(d + 1, cur);
cur *= pfac[d];
}
}
int solve(int n) {
divide(n);
fac.clear();
dfs(1, 1);
int ans = 0;
for (int i = 0; i < fac.size(); i++) {
ans += C[fac[i]];
}
return ans;
}
int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
init();
euler();
int n, T;
cin >> T;
while (T--) {
cin >> n;
if (n & 1) cout << "0" << ENDL;
else cout << solve(n) << ENDL;
}
return 0;
}
思路二
根据如下两个方程 a + b + c = n , a 2 + b 2 = c 2 a+b+c=n,a^2+b^2=c^2 a+b+c=n,a2+b2=c2,我们可以得到 a 2 + b 2 = n − ( a + b ) \sqrt{a^2+b^2}=n-(a+b) a2+b2=n−(a+b),两边开方可以得到 a 2 + b 2 = n 2 − 2 n ( a + b ) + a 2 + b 2 + 2 a b a^2+b^2=n^2-2n(a+b)+a^2+b^2+2ab a2+b2=n2−2n(a+b)+a2+b2+2ab,化简得到 2 n a + 2 n b = n 2 − 2 a b 2na+2nb=n^2-2ab 2na+2nb=n2−2ab,尝试用其他两个数表示 b b b,得出 b = n 2 − 2 n a 2 ( n − a ) b=\frac{n^2-2na}{2(n-a)} b=2(n−a)n2−2na,这时有一个小技巧,令 k = n − a k=n-a k=n−a,然后得出 b = 2 n 2 − 2 n a − n 2 2 k = n − n 2 2 k b=\frac{2n^2-2na-n^2}{2k}=n-\frac{n^2}{2k} b=2k2n2−2na−n2=n−2kn2
然后就是想办法确定 b b b的精确范围,因为直角三角形满足 a < b < c a < b < c a<b<c,那么就是 0 < a < n 3 0<a<\frac{n}{3} 0<a<3n,即 0 < n − k < n 3 0<n-k<\frac{n}{3} 0<n−k<3n,得出 2 n 3 < k < n \frac{2n}{3} < k<n 32n<k<n。又因为 a < b a<b a<b,即 n − k < n − n 2 2 k n-k < n-\frac{n^2}{2k} n−k<n−2kn2,这样解出 2 n < 2 k \sqrt{2}n <2k 2n<2k,再联系上面解出的范围,最终得到 2 n < 2 k < 2 n \sqrt{2}n <2k <2n 2n<2k<2n
于是问题就变成了求出 n 2 n^2 n2的所有因数,然后找到所有满足上述范围的合法的解的个数即可。
注意 n 2 n^2 n2的因子要用 l o n g l o n g long~~long long long存的。
//
// Created by Happig on 2020/10/18
//
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define ENDL "\n"
#define lowbit(x) (x&(-x))
#define mkp(x, y) make_pair(x,y)
#define mem(a, x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 1e7 + 10000;
int p[maxn], num[maxn];
vector<ll> fac;
int cnt;
void getFac(int n) {
cnt = 0;
int m = sqrt(n + 0.5);
for (int i = 2; i <= m; i++) {
if (n % i == 0) {
p[++cnt] = i, num[cnt] = 0;
while (n % i == 0) {
num[cnt]++;
n /= i;
}
}
}
if (n > 1) p[++cnt] = n, num[cnt] = 1;
for (int i = 1; i <= cnt; i++) num[i] <<= 1;
}
void dfs(int d, ll cur = 1) {
if (d == cnt + 1) {
fac.push_back(cur);
return;
}
for (int i = 0; i <= num[d]; i++) {
dfs(d + 1, cur);
cur *= p[d];
}
}
int solve(int n) {
getFac(n);
fac.clear();
dfs(1, 1);
int ans = 0, l = sqrt(2.0) * n, r = 2 * n;
for (auto i: fac) {
if (i & 1) continue;
if (i > l && i < r) ans++;
}
return ans;
}
int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, T;
cin >> T;
while (T--) {
cin >> n;
if (n & 1) cout << 0 << ENDL;
else cout << solve(n) << ENDL;
}
return 0;
}