[bzoj4559] [JLoi2016]成绩比较

Description

G系共有n位同学,M门必修课。这N位同学的编号为0到N-1的整数,其中B神的编号为0号。这M门必修课编号为0到M-

1的整数。一位同学在必修课上可以获得的分数是1到Ui中的一个整数。如果在每门课上A获得的成绩均小于等于B获

得的成绩,则称A被B碾压。在B神的说法中,G系共有K位同学被他碾压(不包括他自己),而其他N-K-1位同学则没

有被他碾压。D神查到了B神每门必修课的排名。这里的排名是指:如果B神某门课的排名为R,则表示有且仅有R-1

位同学这门课的分数大于B神的分数,有且仅有N-R位同学这门课的分数小于等于B神(不包括他自己)。我们需要

求出全系所有同学每门必修课得分的情况数,使其既能满足B神的说法,也能符合D神查到的排名。这里两种情况不

同当且仅当有任意一位同学在任意一门课上获得的分数不同。你不需要像D神那么厉害,你只需要计算出情况数模1

0^9+7的余数就可以了。

Input

第一行包含三个正整数N,M,K,分别表示G系的同学数量(包括B神),必修课的数量和被B神碾压的同学数量。第二

行包含M个正整数,依次表示每门课的最高分Ui。第三行包含M个正整数,依次表示B神在每门课上的排名Ri。保证1

≤Ri≤N。数据保证至少有1种情况使得B神说的话成立。N<=100,M<=100,Ui<=10^9

Output

仅一行一个正整数,表示满足条件的情况数模10^9+7的余数。

Sample Input

3 2 1 
2 2 
1 2 

Sample Output

10

题解

前置知识:容斥思想

此题其实可以分成两部分:

  • 成绩相对关系的限制

  • 成绩大小的限制

那么可以分成两部分考虑,然后乘起来即为最终答案。

相对关系的限制

考虑\(f(i)\)表示恰好有\(i\)个人被碾压的方案数,则可以对于每个科目进行考虑乘起来,然后减去不合法的,即:

\[f(i)=\binom{n-1}{i} \prod_{j=1}^m \binom{n-i-1}{rk(j)-1} -\sum_{j=i+1}^{n}\binom{j}{i}f(j) \]

式子前半部分考虑,当前剩下了\(n-i-1\)个人可以大于他,要从中选出\(rk(j)-1\)个人。

然后后半部分可以考虑,对于一个恰好有\(j\)个人的方案,会被算到\(\binom{j}{i}\)次,减掉就好了。

成绩大小的限制

同样可以对于每个科目分别计算。

枚举当前的成绩\(x\),然后大于和小于等于他的人都任选,在加起来,即:

\[ans=\sum_{x=1}^{lim} x^{n-rk}*(s-x)^{rk-1} \]

\(lim\)为当前成绩上限。由于\(lim\)的范围非常大,这样算显然不行,我们二项式展开这个式子,整理下:

\[\begin{align} ans &= \sum_{x=1}^{lim}x^{n-rk}*\sum_{i=0}^{rk-1}\binom{rk-1}{i}s^{rk-1-i}(-1)^ix^i\\ &= \sum_{i=0}^{rk-1}(-1)^i\binom{rk-1}{i}x^{n-rk+i}\sum_{x=1}^{lim}s^{rk-1-i} \end {align} \]

注意到后面一项为这样的形式:

\[g(n)=\sum_{i=1}^si^n \]

观察下下面的式子:

\[\begin{align} (s+1)^{n+1}-s^{n+1}&=\sum _{i=0}^{n} \binom{n+1}{i}s^{i}\\ s^{n+1}-(s-1)^{n+1}&=\sum _{i=0}^{n} \binom{n+1}{i}(s-1)^i\\ &~~\vdots\\ 2^{n+1}-1^{n+1}&=\sum_{i=0}^{n}\binom{n+1}{i}*1^i \end {align} \]

然后将所有式子加起来,可以得到:

\[\begin{align} (s+1)^{n+1}-1&=\sum_{i=0}^{n}\binom{n}{i}g(i)\\ (s+1)^{n+1}-1&=\sum_{i=0}^{n-1}\binom{n}{i}g(i)+g(n)*(n+1)\\ g(n)&=\frac{(s+1)^{n+1}-1-\sum_{i=0}^{n-1}\binom{n}{i}g(i)}{n+1} \end {align} \]

然后我们对于每个\(s\)大力算出\(g\),然后就做完了。

时间复杂度\(\Theta(n^3)\)

#include<bits/stdc++.h>
using namespace std;
 
#define void inline void
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
 
const int mod = 1e9+7; 
const int maxn = 200+10;
 
int n,m,k,lim[maxn],rk[maxn],f[maxn],ans,fac[maxn],ifac[maxn],g[maxn];
 
int binom(int x,int y) {return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
 
int qpow(int a,int x) {
    int res=1;
    for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
    return res;
}
 
void solve1() {
    for(int i=n-1;i>=k;i--) {
        int res=binom(n-1,i);
        for(int j=1;j<=m;j++) res=(1ll*res*binom(n-i-1,rk[j]-1)%mod)%mod;
        for(int j=i+1;j<=n-1;j++) res=(res-1ll*f[j]*binom(j,i)%mod)%mod;
        f[i]=(res+mod)%mod;//write(f[i]);
    }
}
 
void solve2() {
    ans=1;
    for(int s=1;s<=m;s++) {
        int res=0;
        g[0]=lim[s];
        for(int j=1;j<=n+1;j++) {
            g[j]=qpow(lim[s]+1,j+1)-1;
            for(int i=0;i<j;i++) g[j]=(g[j]-1ll*binom(j+1,i)*g[i])%mod;
            g[j]=1ll*g[j]*qpow(j+1,mod-2)%mod;
            //printf("%d %d\n",j,g[j]);
        }
        for(int i=0,p=1;i<=rk[s]-1;i++) res=(res+1ll*binom(rk[s]-1,i)*qpow(lim[s],rk[s]-i-1)%mod*g[n-rk[s]+i]*p%mod)%mod,p=-p;
        res=(res+mod)%mod;//write(res);
        ans=1ll*ans*res%mod;
    }
}
 
int main() {
    read(n),read(m),read(k);fac[0]=ifac[0]=1;
    for(int i=1;i<=200;i++) fac[i]=1ll*fac[i-1]*i%mod;
    ifac[200]=qpow(fac[200],mod-2);
    for(int i=200-1;i;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    for(int i=1;i<=m;i++) read(lim[i]);
    for(int i=1;i<=m;i++) read(rk[i]);
    solve1();solve2();
    write(1ll*ans*f[k]%mod);
    return 0;
}

posted @ 2018-11-29 09:50  Hyscere  阅读(255)  评论(0编辑  收藏  举报