【題解】LuoGu4561:[JXOI2018]排序問題

原題傳送門
轉化問題:每次令[l,r][l,r]中出現次數最少的數出現次數加1,加mm
模擬題

先統計出不在[l,r][l,r]中的答案
再統計出[l,r][l,r]的數各出現了幾次,然後就是一層一層的填上去,填到不能填爲止

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章