zoukankan      html  css  js  c++  java
  • [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)=inom{n-1}{i} prod_{j=1}^m inom{n-i-1}{rk(j)-1} -sum_{j=i+1}^{n}inom{j}{i}f(j) ]

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

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

    成绩大小的限制

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

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

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

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

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

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

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

    观察下下面的式子:

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

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

    [egin{align} (s+1)^{n+1}-1&=sum_{i=0}^{n}inom{n}{i}g(i)\ (s+1)^{n+1}-1&=sum_{i=0}^{n-1}inom{n}{i}g(i)+g(n)*(n+1)\ g(n)&=frac{(s+1)^{n+1}-1-sum_{i=0}^{n-1}inom{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('
    ');}
     
    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
    ",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;
    }
    
    
  • 相关阅读:
    win10- *.msi 软件的安装,比如 SVN安装报2503,2502
    Java-byte[]与16进制字符串互转
    log4j 日志脱敏处理 + java properties文件加载
    CentOS7编译安装SVN(subversion1.9.7)
    Samba安装与配置
    php 实现redis发布订阅消息及时通讯
    PHP中使用ActiveMQ实现消息队列
    sphinx 配置文件全解析
    nginx和apache 配置
    php实现汉诺塔问题
  • 原文地址:https://www.cnblogs.com/hbyer/p/10036444.html
Copyright © 2011-2022 走看看