题意
给出 (n) 条边,问能组成几种等腰梯形。要满足一下要求:
- 不能是矩形
- 所有边长的 gcd 是1
- 全等的梯形只算一次
思路
枚举梯形的腰 (x) 和顶 (y),可以求出底的范围为:([y+1,2*x+y-1])
因为还有一个条件为 (gcd) 为 1,那么我们可以预处理出一个数组 (vec[N][N]),(vec[i]) 存放和 (i) 互质的所有边长。
对于腰 (x) 和顶 (y)我们在 vec[(gcd(x,y))] 中找在区间 ([y+1,2*x+y-1]) 的个数,这时候特判一下 (x) 和 (y) 的个数避免多算。
比赛的时候因为我读错题意,以为矩形也可以,疯狂WA。。。赛后对拍发现不对劲,修改一下底的范围就过了。
代码
/*
* @Autor: valk
* @Date: 2020-08-21 11:06:28
* @LastEditTime: 2020-10-16 20:47:12
* @Description: 如果邪恶 是华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <algorithm>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
int arr[N], num[N];
vector<int> vec[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
num[arr[i]]++;
}
sort(arr + 1, arr + 1 + n);
n = unique(arr + 1, arr + 1 + n) - arr - 1;
for (int i = 1; i <= 10000; i++) {
for (int j = 1; j <= n; j++) {
if (__gcd(i, arr[j]) == 1) {
vec[i].pb(arr[j]);
}
}
}
ll ans = 0;
for (int i = 1; i <= n; i++) { //腰
if (num[arr[i]] < 2)
continue;
for (int j = 1; j <= n; j++) { //顶
if (i == j && num[arr[i]] < 3)
continue;
int l = arr[j] + 1, r = arr[j] + 2 * arr[i] - 1;
int gcd = __gcd(arr[i], arr[j]);
int R = upper_bound(vec[gcd].begin(), vec[gcd].end(), r) - vec[gcd].begin();
int L = upper_bound(vec[gcd].begin(), vec[gcd].end(), l - 1) - vec[gcd].begin();
int temp = R - L;
if (num[arr[j]] == 1 && __gcd(arr[j], gcd) == 1 && arr[j] >= l && arr[j] <= r) {
temp--;
}//如果边长为arr[j]的边只有一条,并且还被计算到了底中,那么要减去这个
if (num[arr[i]] == 2 && __gcd(gcd, arr[i]) == 1 && arr[i] >= l && arr[i] <= r) {
temp--;
}//腰同理
ans += temp;
}
}
printf("%lld
", ans);
return 0;
}
/*
6
1 1 10 8 8 5
*/