原題傳送門
轉化問題:每次令中出現次數最少的數出現次數加1,加次
模擬題
先統計出不在中的答案
再統計出的數各出現了幾次,然後就是一層一層的填上去,填到不能填爲止
Code:
#include <bits/stdc++.h>
#define maxn 12000010
#define N 200010
#define LL long long
using namespace std;
const LL qy = 998244353;
LL fac[maxn], a[N], b[N], ans, sum;
int cnt, num, n, m, l, r;
inline int read() {
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
LL ksm(LL n, LL k){
if (!k) return 1;
LL sum = ksm(n, k >> 1);
sum = sum * sum % qy;
if (k & 1) sum = sum * n % qy;
return sum;
}
int main(){
fac[0] = 1;
for (int i = 1; i < maxn; ++i) fac[i] = fac[i - 1] * i % qy;
int T = read();
while (T--){
n = read(), m = read(), l = read(), r = read(), ans = 1, cnt = 0, num = 0, sum = r - l + 1;
for (int i = 1; i <= n; ++i) a[i] = read();
sort(a + 1, a + 1 + n);
for (int i = 1, j = 1; i <= n; i = j){
while (a[i] == a[j] && j <= n) ++j;
if (a[i] < l || a[i] > r) ans = ans * fac[j - i] % qy; else b[++cnt] = j - i, --sum;
}
sort(b + 1, b + 1 + cnt);
for (int i = 1, j = 1; i <= cnt; i = j){
while (b[i] == b[j] && j <= cnt) ++j;
a[++num] = b[i], b[num] = j - i;
}
a[++num] = 1e9, b[num] = 0;
for (int i = 1, M = m; i <= num; ++i){
LL x = (a[i] - a[i - 1]) * sum;
if (x <= M) M -= x, sum += b[i]; else{
for (int j = i; j < num; ++j) ans = ans * ksm(fac[a[j]], b[j]) % qy;
ans = ans * ksm(fac[a[i - 1] + M / sum], sum - M % sum) % qy * ksm(fac[a[i - 1] + M / sum + 1], M % sum) % qy;
break;
}
}
printf("%lld\n", fac[n + m] * ksm(ans, qy - 2) % qy);
}
return 0;
}