CF1513E-Cost Equilibrium

题目链接
思路
所有数之和sum除以n就是所求的平均值。如果\(sum \mod n \neq 0\)那么无解,假设\(x=sum/n.\)那么小于x的值就是汇点,大于x的值就是源点。令小于x的数有cnt1个,大于x的数有cnt2个,那么等于x的数就有\(n-cnt1-cnt2\)个。因为等于x的数无影响,所以可以随便放,那么就是在n个位置中找x个位置的方案数,即是\(cnt = C_{n}^{n-cnt1-cnt2}\)
接下来考虑源点和汇点的情况:
若源点个数 \(\leq0\) 或者 汇点个数 \(\leq 0\) ,那么任意的排列方式都是可以的。所以只需要计算一下他们的多重全排列方案数就行了。最后答案再乘上等于x的数的方案数即可。
(多重全排列:假设有n个不同的数,现在有\(k_1\)\(a_1\)\(k_2\)\(a_2\)\(k_3\)\(a_3\),那么其多重全排列数就是\(\frac{(k_1+k_2+k_3)!}{k_1!*k_2!*k_3!}\),意思就是对于原数组先进行全排列,然后对于相同的数字自己有\(k_i!\)种内部相同的全排列数,除去就行)
若源点个数 \(> 1\) 并且 汇点个数 \(>1\),那么就必须要让汇点的所有点在一侧,源点的所有点在一侧,两类点不能交错放在一起。例如1212或者1221这种,因为当前源点既可以选择进的汇点,也可以选择远的汇点。那就分别考虑一侧全部是源点的多重全排列数,另一侧全部是汇点的多重全排列数,最后答案乘上等于x的方案数就行了。
具体可以看代码更为清楚。
代码

/*人一我百,人十我万*/
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, LL> PIL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
#define x first
#define y second
const int N = 1e5 + 10, M = 1e5 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
#define gcd __gcd

int a[N], b[N], c[N];
map<int, int> cnt;
LL f[N], inv[N];

LL kpow(LL a, LL n) {
    LL res = 1;
    while(n) {
        if(n & 1) res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}

LL C(LL n, LL m) {
    if(m > n) return 0;
    return f[n] * inv[m] % mod * inv[n - m] % mod;
}

void init(int n) {
    f[0] = 1;
    inv[0] = 1;
    for(int i = 1; i <= n; i++) {
        f[i] = f[i - 1] * i % mod;
        inv[i] = inv[i - 1] * kpow(i, mod - 2) % mod;
    }
}

void solve() {
    int n;
    scanf("%d", &n);
    LL sum = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        cnt[a[i]]++;
        sum += a[i];
    }
    if(sum % n != 0) {
        puts("0");
        return;
    }
    int idx1 = 0, idx2 = 0;
    int x = sum / n;
    for(int i = 1; i <= n; i++) {
        if(a[i] < x) b[++idx1] = a[i];
        else if(a[i] > x) c[++idx2] = a[i];
    }
    sort(b + 1, b + 1 + idx1);
    sort(c + 1, c + 1 + idx2);
    int len1 = unique(b + 1, b + 1 + idx1) - b - 1;
    int len2 = unique(c + 1, c + 1 + idx2) - c - 1;
    if(idx1 <= 1 || idx2 <= 1) {
        LL res = C(n, n - idx1 - idx2) * f[idx1 + idx2] % mod;
        if(idx1) {
            for(int i = 1; i <= len1; i++) {
                res = res * inv[cnt[b[i]]] % mod;
            }
        }
        if(idx2) {
            for(int i = 1; i <= len2; i++) {
                res = res * inv[cnt[c[i]]] % mod;
            }
        }
        printf("%lld\n", res);
        return;
    }

    LL res = C(n, n - idx1 - idx2) * f[idx1] % mod * f[idx2] % mod;
    if(idx1) {
        for(int i = 1; i <= len1; i++) {
            res = res * inv[cnt[b[i]]] % mod;
        }
    }
    if(idx2) {
        for(int i = 1; i <= len2; i++) {
            res = res * inv[cnt[c[i]]] % mod;
        }
    }
    printf("%lld\n", res * 2 % mod);
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    // std::ios::sync_with_stdio(false); 
    // cin.tie(0); cout.tie(0);

    // int t; cin >> t; while(t--)
    init(1e5);
    solve();
    return 0;
}
posted @ 2021-07-06 10:45  这知识他不进我的脑子  阅读(39)  评论(0编辑  收藏  举报