51Nod - 1165 整边直角三角形的数量(两种解法:本原直角三角形/求解方程的解数)

传送门


题目大意

给出直角三角形的周长 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=n22n(a+b)+a2+b2+2ab,化简得到 2 n a + 2 n b = n 2 − 2 a b 2na+2nb=n^2-2ab 2na+2nb=n22ab,尝试用其他两个数表示 b b b,得出 b = n 2 − 2 n a 2 ( n − a ) b=\frac{n^2-2na}{2(n-a)} b=2(na)n22na,这时有一个小技巧,令 k = n − a k=n-a k=na,然后得出 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=2k2n22nan2=n2kn2

然后就是想办法确定 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<nk<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} nk<n2kn2,这样解出 2 n < 2 k \sqrt{2}n <2k 2 n<2k,再联系上面解出的范围,最终得到 2 n < 2 k < 2 n \sqrt{2}n <2k <2n 2 n<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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值