[JLOI 2016]成績比較

Description

題庫連接\(\text{bzoj}\) 不知道爲何過不了啊... \(\text{luogu loj}\) 都能過...就給 \(\text{luogu}\) 的連接了...)c++

共有 \(n\) 位同窗, \(M\) 門必修課。一位同窗在必修課上能夠得到的分數是 \(1\)\(U_i\) 中的一個整數。ui

若是在每門課上 \(A\) 得到的成績均小於等於 \(B\) 得到的成績,則稱 \(A\)\(B\) 碾壓。在 \(B\) 神的說法中,共有 \(K\) 位同窗被他碾壓(不包括他本身)。spa

\(B\) 神在第 \(i\) 門必修課中排名爲 \(R_i\) 。這裏的排名是指:若是 \(B\) 神某門課的排名爲 \(R\) ,則表示有且僅有 \(R-1\) 位同窗這門課的分數大於 \(B\) 神的分數,有且僅有 \(N-R\) 位同窗這門課的分數小於等於 \(B\) 神(不包括他本身)。code

咱們須要求出全系全部同窗每門必修課得分的狀況數,使其既能知足B神的說法,也能符合排名。這裏兩種狀況不一樣當且僅當有任意一位同窗在任意一門課上得到的分數不一樣。ip

計算出狀況數模 \(10^9+7\) 的。get

\(N\leq 100,M\leq 100,Ui\leq 10^9\)it

Solution

因爲只有 \(k\) 名同窗被碾壓,故要保證其他的 \(n-1-k\) 名同窗至少有一門分數要高於他。io

咱們有 \(n-1\choose k\) 種方案選出被碾壓的 \(k\) 我的,對於剩下的 \(n-1-k\) 我的,咱們記 \(f_x\) 爲至多有 \(x\) 我的知足至少一門分數高於他,那麼 \(f_x=\prod\limits_{i=1}^m{x\choose R_i-1}\) 。再設 \(g_x\) 爲恰有 \(x\) 我的知足至少一門分數高於他,顯然咱們要求的是 \(g_{n-k-1}\)class

容易獲得方法

\[f_x=\sum_{i=1}^x {x\choose i}g_i\]

由二項式反演,獲得

\[g_x=\sum_{i=1}^x (-1)^{x-i}{x\choose i}f_i\]

那麼

\[g_{n-k-1}=\sum_{i=1}^{n-k-1}(-1)^{n-k-1-i}{n-k-1\choose i}\prod_{j=1}^m{i\choose R_j-1}\]

不過這隻考慮了合法的安排相對分數高低狀況,尚未考慮具體分數的關係。

不妨記 \(S\) 爲一種人員安排狀況下不一樣的分數安排方法。

咱們枚舉他的分數獲得

\[\begin{aligned}S&=\prod_{i=1}^m\sum_{j=1}^{U_i}j^{n-R_i}(U_i-j)^{R_i-1}\\&=\prod_{i=1}^m\sum_{j=1}^{U_i}j^{n-R_i}\sum_{k=0}^{R_i-1}(-1)^k{R_i-1\choose k}j^kU_i^{R_i-1-k}\\&=\prod_{i=1}^m\sum_{j=1}^{U_i}\sum_{k=0}^{R_i-1}j^{n-R_i+k}(-1)^k{R_i-1\choose k}U_i^{R_i-1-k}\\&=\prod_{i=1}^m\sum_{k=0}^{R_i-1}(-1)^k{R_i-1\choose k}U_i^{R_i-1-k}\sum_{j=1}^{U_i}j^{n-R_i+k}\end{aligned}\]

注意到 \(Q=\sum\limits_{j=1}^{U_i}j^{n-R_i+k}\) 中的 \(U_i\) 會很大,顯然不能直接枚舉,咱們能夠插值解決。預處理出 \(S\) 的複雜度是 \(O(mn^2)\) 的。

最終答案就是

\[{n-1\choose k}g_{n-k-1}S\]

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 233+5, yzh = 1e9+7;

int n, m, k, U[N], R[N];
int fac[N], ifac[N];
int prime[N], tot, isprime[N], f[N], s1[N], s2[N];

int quick_pow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b&1) ans = 1ll*ans*a%yzh;
        b >>= 1, a = 1ll*a*a%yzh;
    }
    return ans;
}
int C(int n, int m) {return 1ll*fac[n]*ifac[m]%yzh*ifac[n-m]%yzh; }
int lagrange(int *y, int k, int xi) {
    int ans = 0; ++k;
    s1[0] = xi, s2[k+1] = 1;
    for (int i = 1; i <= k; i++) s1[i] = 1ll*s1[i-1]*(xi-i)%yzh;
    for (int i = k; i >= 0; i--) s2[i] = 1ll*s2[i+1]*(xi-i)%yzh;
    for (int i = 0; i <= k; i++)
        (ans += 1ll*y[i]*(i == 0 ? 1 : s1[i-1])%yzh*s2[i+1]%yzh*ifac[i]%yzh*((k-i)&1 ? -1 : 1)*ifac[k-i]%yzh) %= yzh;
    return ans;
}
int getQ(int xi, int k) {
    tot = 0; memset(isprime, 1, sizeof(isprime));
    isprime[1] = 0; f[0] = 0, f[1] = 1;
    for (int i = 2; i <= k+1; i++) {
        if (isprime[i]) prime[++tot] = i, f[i] = quick_pow(i, k);
        for (int j = 1; j <= tot && i*prime[j] <= k+1; j++) {
            isprime[i*prime[j]] = 0, f[i*prime[j]] = 1ll*f[i]*f[prime[j]]%yzh;
            if (i%prime[j] == 0) break;
        }
    }
    for (int i = 1; i <= k+1; i++) (f[i] += f[i-1]) %= yzh;
    if (xi <= k+1) return f[xi];
    return lagrange(f, k, xi);
}
int getS() {
    int ans = 1;
    for (int i = 1; i <= m; i++) {
        int sum = 0;
        for (int k = 0; k <= R[i]-1; k++)
            if (k&1) (sum -= 1ll*C(R[i]-1, k)*quick_pow(U[i], R[i]-1-k)%yzh*getQ(U[i], n-R[i]+k)%yzh) %= yzh;
            else (sum += 1ll*C(R[i]-1, k)*quick_pow(U[i], R[i]-1-k)%yzh*getQ(U[i], n-R[i]+k)%yzh) %= yzh;
        ans = 1ll*ans*sum%yzh;
    }
    return ans;
}
void work() {
    scanf("%d%d%d", &n, &m, &k);
    fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
    for (int i = 2; i < N; i++) ifac[i] = -1ll*yzh/i*ifac[yzh%i]%yzh;
    for (int i = 2; i < N; i++)
        ifac[i] = 1ll*ifac[i-1]*ifac[i]%yzh,
        fac[i] = 1ll*fac[i-1]*i%yzh;
    for (int i = 1; i <= m; i++) scanf("%d", &U[i]);
    for (int i = 1; i <= m; i++) scanf("%d", &R[i]);
    int S = getS(), ans = 0;
    for (int i = 1; i <= n-k-1; i++) {
        int sum = 1;
        for (int j = 1; j <= m; j++) sum = 1ll*sum*C(i, R[j]-1)%yzh;
        if ((n-k-1-i)&1) (ans -= 1ll*sum*C(n-k-1, i)%yzh) %= yzh;
        else (ans += 1ll*sum*C(n-k-1, i)%yzh) %= yzh;
    }
    ans = 1ll*ans*S%yzh*C(n-1, k)%yzh;
    printf("%d\n", (ans+yzh)%yzh);
}
int main() {work(); return 0; }
相關文章
相關標籤/搜索