【2019 CCPC 江西省赛】Trap 枚举

C - Trap

题意

给出 (n) 条边,问能组成几种等腰梯形。要满足一下要求:

  1. 不能是矩形
  2. 所有边长的 gcd 是1
  3. 全等的梯形只算一次

思路

枚举梯形的腰 (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 
*/
原文地址:https://www.cnblogs.com/valk3/p/13832331.html