题解 P3799 妖梦拼木棒

题意简述

\(n\) 根木棒,第 \(i\) 跟木棒的长度为 \(a_i\) ,现在从中选 \(4\) 根,想要组成一个正三角形,问有几种选法?

答案对 \(10^9+7\) 取模。

\(1 \leq n \leq 10^5 ,1 \leq a_i \leq 5\times 10^3\)

Solution

选四根组成一个正三角形,也就是说必须选出两根长度相同的(设这个长度为 \(x\)),还要再选出两根长度和为 \(x\) 的木棒。

注意到 \(a_i \leq 5\times 10^3\) ,可以考虑先开个桶记录下每种木棒的长度有多少根,然后枚举这个 \(x\) , 再枚举拼成 \(x\) 的两根木棒的长度 \(i,j\) 即可通过。

那么接下来就是对于每个 \(x\) 分别计算了。记长度为 \(x\) 的木棒有 \(b_x\) 个,那么先从这 \(b_x\) 个木棒中选出 \(2\) 根,方案数是 \(\tbinom{b_x}{2}\) ,然后 \(i,j\) 的话要分两种情况:

  • \(i \neq j\) ,那么相当于从长度为 \(i\) 的木棒里随便选一根,再从长度为 \(j\) 的木棒里随便选一跟,方案数为 \(b_i\times b_j\)
  • \(i=j\) ,那么相当于从长度为 \(i\) 的木棒里选出两根,方案数为 \(\tbinom{b_i}{2}\)

木棒最长为 \(x\) 的方案数是 \(\tbinom{b_x}{2}\) 乘枚举 \(i,j\) 时的方案和,原理是乘法原理。

总的方案数就是每种情况的和。注意乘法会爆 int ,要临时转化成 long long

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <queue>
typedef long long LL;
using namespace std;
inline int read() {
    int num = 0 ,f = 1; char c = getchar();
    while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar();
    while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar();
    return num * f;
}
const int N = 5e3 + 5 ,mod = 1e9 + 7 ,inv2 = (mod + 1) / 2;
inline int C(int n) {
    return (LL)n * (n - 1) % mod * inv2 % mod;
}
int cnt[N] ,ans ,n;
signed main() {
    n = read();
    for (int i = 1; i <= n; i++) {
        int x = read();
        cnt[x]++;
    }
    for (int i = 2; i <= 5000; i++)
        if (cnt[i] >= 2) {
            int res = 0;
            for (int j = 1; j <= i / 2; j++)
                if (i - j != j)
                    res = (res + (LL)cnt[j] * cnt[i - j] % mod) % mod;
                else
                    res = (res + (LL)cnt[i / 2] * (cnt[i / 2] - 1) / 2 % mod) % mod;
            ans = (ans + (LL)res * C(cnt[i]) % mod) % mod;
        }
    printf("%d\n" ,ans);
    return 0;
}
posted @ 2021-08-26 21:02  recollector  阅读(103)  评论(0编辑  收藏  举报