题意:给 n 条边,问能构成多少种不是矩形的等腰梯形。
思路:预处理出和 [2, 10000] 中每个数互质的边,枚举上底和下底,在与当前gcd互质的边集中二分符合能够组成四边形条件的长度。注意除去底边和腰长相等但是该长度的边不够的情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const db eps = 1e-7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 2e3 + 7;
const int M = 1e4 + 7;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
vector<int>lis[M];
int a[N], b[N], cnt[M], n;
int main() {
while(~scanf("%d", &n)) {
for(int i = 1; i < M; ++i) cnt[i] = 0;
for(int i = 1; i < M; ++i) lis[i].clear();
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
++cnt[a[i]];
}
sort(a + 1, a + n + 1);
int tot1 = unique(a + 1, a + n + 1) - a - 1;
int tot2 = 0;
for(int i = 1; i <= tot1; ++i)
if(cnt[a[i]] >= 2) b[++tot2] = a[i];
for(int i = 1; i < M; ++i)
for(int j = 1; j <= tot2; ++j)
if(gcd(i, b[j]) == 1) lis[i].emplace_back(b[j]);
ll ans = 0;
for(int i = 1; i <= tot1; ++i) {
for(int j = 1; j < i; ++j) {
int lim = (a[i] - a[j] + 2) / 2;
int tmp = gcd(a[i], a[j]);
int it = lower_bound(lis[tmp].begin(), lis[tmp].end(), lim) - lis[tmp].begin();
ans += lis[tmp].size() - it;
///不互质的两条边不会搜到同长度的腰
if(tmp == 1) {
///只有两个同长度的边,长度符合要求,但不可既作为底也作为腰
if(cnt[a[i]] == 2 && a[i] >= lim) --ans;
if(cnt[a[j]] == 2 && a[j] >= lim) --ans;
}
}
}
printf("%d\n", ans);
}
return 0;
}