5322: [Jxoi2018]排序问题

5322: [Jxoi2018]排序问题

链接

分析:

  每次选一个出现次数最小的。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int mod = 998244353;
int fac[10200005], a[200005], b[200005]; 

int ksm(int a,int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}
void solve() {
    int n = read(), m = read(), l = read(), r = read(), tot = 0, cnt = 0, f = r - l + 1, ans = 1;
    for (int i = 1; i <= n; ++i) a[i] = read();
    sort(a + 1, a + n + 1);
    
    for (int i = 1, j = 1; i <= n; i = j) {
        while (j <= n && a[i] == a[j]) j ++;
        if (l <= a[i] && a[i] <= r) b[++tot] = j - i, f --;
        else ans = 1ll * ans * fac[j - i] % mod;
    }
    
    sort(b + 1, b + tot + 1);
    for (int i = 1, j = 1; i <= tot; i = j) {
        while (j <= tot && b[i] == b[j]) j ++;
        ++cnt; a[cnt] = b[i], b[cnt] = j - i;
    }
    a[++cnt] = 1e9, b[cnt] = 1;
    
    for (int i = 1, M = m; i <= cnt; ++i) {
        LL c = a[i] - a[i - 1], t = c * f;
        if (t > M) {
            int x = a[i - 1] + (M / f), y = M % f;
            ans = 1ll * ans * ksm(fac[x], f - y) % mod * ksm(fac[x + 1], y) % mod;
            for (int j = i; j < cnt; ++j) 
                ans = 1ll * ans * ksm(fac[a[j]], b[j]) % mod;
            break;
        }
        M -= t, f += b[i];
    }
    ans = 1ll * fac[n + m] * ksm(ans, mod - 2) % mod;
    printf("%d\n", ans);
}
int main() {
    fac[0] = 1;
    for (int i = 1; i <= 10200000; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
    for (int T = read(); T --; solve());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/10520727.html