• [JLOI2016] 成绩比较


    题意:

    有n个人,m门课,每个人在每门课的得分是一个$[1,u_i ]$之间的整数。

    你知道自己在每门课的排名$r_i$,即有$r_i-1$个人得分高于你,$n-r_i$个人得分不高于你(不含自己)。

    求你恰好碾压k个人的方案数,a碾压b的含义为a每门课的得分都不低于b的得分。

    $n,mleq 100,u_i leq 10^{9}$。

    题解:

    一看到恰好k个就想到一个套路:$Num(恰好k个)=Num(钦定k个)-Num(钦定k+1个)+cdots$。

    此时我们要考虑到一个严重的问题:(以下为防止组合数越界有做简单变式)

    这题从n-1个人里选x个被碾压的方案数到底是${n-1}choose {n-1-x}$还是${{n-1} choose {n-1-k}}{{n-1-k}choose {n-1-x}}$?

    首先回顾一下${n}choose x$和${{n} choose m}{mchoose x}$的本质区别:前者是分两个集合,后者是分三个集合。

    也就是说对于每个大小为x的集合S,前者只被算了一遍,后者被算了${n-x}choose{m-x}$遍。

    那么我们考虑这道题容斥的底层过程:有两个大小为k的集合S1和S2,它们的并集是大小为k+1的S3。

    那S3是被算了一遍还是被算了${{k+1}choose{k}}$遍呢?显然是后者,于是一开始就应该用后者计算。

    (upd:另一种解释:是对于每个集合容斥而不是对于集合大小容斥,所以每次必须钦定k个不动。)

    回到容斥,答案就是

    ${n-1choose {n-1-k}}sum limits_{j=k}^{n-1}{(-1)^{j-k}{n-1-kchoose {n-1-j}}prod limits_{i=1}^{m}{n-1-jchoose n-r_i -j}sum limits_{x=1}^{u_i}{x^{n-r_i}(u_i -x)^{r_i -1}}}$

    最后面那个式子可以用二项式定理拆一下,我是在容斥里面写了个子容斥。(所以说我nt呢)

    大概形如

    ${n-1choose {n-1-k}}sum limits_{j=k}^{n-1}{(-1)^{j-k}{n-1-kchoose {n-1-j}}prod limits_{i=1}^{m}{n-1-jchoose n-r_i -j}sum limits_{x=1}^{u_i}{x^{n-r_i}(u_i -x)^{r_i -1}}}$

    $={n-1choose {n-1-k}}sum limits_{j=k}^{n-1}{(-1)^{j-k}{n-1-kchoose {n-1-j}}prod limits_{i=1}^{m}{n-1-jchoose n-r_i -j}sum limits_{l=n-r_i}^{n-1}{(-1)^{l-(n-r_i )}{r_i -1choose n-1-l}u_{i}^{n-1-l}sum limits_{x=1}^{u_i}x^{l}}}$

    考虑原式的组合意义不难得到该容斥,最后那个式子直接拉格朗日插值出来就好了。

    复杂度$O(mn^{3})$。上界为预处理插值,可以优化到$O(mn^{2})$,不过……

    套路:

    • 形如$Num(恰好k个)=Num(钦定k个)-Num(钦定k+1个)+cdots$的容斥$ ightarrow$每个大小为k+1的集合被计算$k+1choose k$次。(大部分时候k为0所以区别不开)
    • 容斥时:注意区分对集合容斥和对集合大小容斥的区别。

    代码:

    #include<bits/stdc++.h>
    #define maxn 205
    #define maxm 500005
    #define inf 0x7fffffff
    #define mod 1000000007
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    struct node{ll x,y;}tp[maxn];
    ll C[maxn][maxn],inv[maxn],R[maxn],U[maxn],L[maxn][maxn]; 
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline ll pw(ll a,ll b){ll r=1;while(b)r=(b&1)?r*a%mod:r,a=a*a%mod,b>>=1;return r;}
    inline void init(ll n){
        C[0][0]=1;
        for(ll i=1;i<=n;i++){
            C[i][0]=1;
            for(ll j=1;j<=i;j++)
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
    }
    inline ll Lagrange(ll x,ll n){
        for(ll i=1;i<=n+2;i++)
            tp[i].x=i,tp[i].y=(tp[i-1].y+pw(i,n))%mod;
        for(ll i=-n-2;i<=n+2;i++)
            inv[i+n+2]=pw((i+mod)%mod,mod-2);
        ll ans=0;
        for(ll i=1;i<=n+2;i++){
            ll res=tp[i].y;
            for(ll j=1;j<=n+2;j++){
                if(j==i) continue;
                res=res*(x-tp[j].x+mod)%mod*inv[tp[i].x-tp[j].x+n+2]%mod;
            }
            ans=(ans+res)%mod;
        }
        return ans;
    }
    
    int main(){
        ll n=read(),m=read(),K=read(),mn=inf;
        for(ll i=1;i<=m;i++) U[i]=read();
        for(ll i=1;i<=m;i++) R[i]=read(),mn=min(n-R[i],mn);
        init(n); ll ans=0;
        for(ll i=1;i<=m;i++)
            for(ll j=0;j<=n-1;j++){
                if(j==0) L[i][j]=U[i];
                else L[i][j]=Lagrange(U[i],j);
            }
        for(ll k=K,t1=1;k<=mn;k++,t1=t1*(mod-1)%mod){
            ll r1=1;
            for(ll i=1;i<=m;i++){
                ll t=n-R[i],r2=0;
                for(ll j=t,t2=1;j<=n-1;j++,t2=t2*(mod-1)%mod)
                    r2=(r2+t2*C[n-1-t][n-1-j]%mod*pw(U[i],n-1-j)%mod*L[i][j]%mod)%mod;
                r1=r1*r2%mod*C[n-1-k][t-k]%mod;
            }
            ans=(ans+r1*t1%mod*C[n-1-K][n-1-k]%mod)%mod;
        }
        printf("%lld
    ",ans*C[n-1][K]%mod);
        return 0;
    }
    成绩比较
  • 相关阅读:
    1、接口测试全流程
    7、执行 suite 后,result.html 测试报告中,测试结果全部显示为通过原因分析
    6、Python 中 利用 openpyxl 读 写 excel 操作
    5、Python 基础类型 -- Dictionary 字典类型
    4、Python 基础类型 -- Tuple 元祖类型
    cp: omitting directory”错误的解释和解决办法
    c++ 之bind使用
    Linux查找–find命令
    lsof命令总结
    Linux查看端口、进程情况及kill进程
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13290090.html
Copyright © 2020-2023  润新知