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;
}