zoukankan      html  css  js  c++  java
  • bzoj4559&&dtoj#2672. 成绩比较 (mark)

    题目描述:

    THU 的 G 系中有许许多多的大牛,比如小 R 的室友 B 神。B 神已经厌倦了与其他的同学比较 GPA(Grade Point Average,平均学分绩),他只在意 G 系中共有多少同学被他“碾压”。

    B 神声称,在 G 系共有 $k$ 位同学被他碾压。同是 G 系大牛的 D 神则认为 B 神在吹牛,他查到了 B 神每门必修课在 G 系的排名。他用了 $173$ 毫秒的时间就计算出了有多少种情况使得 B 神所说的话成立。现在他想考考聪明的你,看你是否也能求出这个情况数。

    G 系共有 $n$ 位同学,$m$ 门必修课。这 $n$ 位同学的编号为 $0$ 到 $n - 1$ 的整数,其中 B 神的编号为 $0$ 号。这 $m$ 门必修课编号为 $0$ 到 $m - 1$ 的整数。如果在每门课上 A 获得的成绩均小于等于 B 获得的成绩,则称 A 被 B 碾压。在 B 神的说法中,G 系共有 $k$ 位同学被碾压(不包括他自己),而其他 $n - k - 1$ 名同学则没有被他碾压。

    D 神查到了 B 神每门必修课的排名。这里的排名是指,如果 B 神某门课的排名为 $r$,则表示有且仅有 $r - 1$ 位同学这门课的分数大于 B 神的分数,有且仅有 $n - r$ 位同学这门课的分数小于等于 B 神(不包括他自己)。

    我们需要求出全系所有同学每门必修课得分的情况数,使其既能满足 B 神的说法,也能符合 D 神查到的排名。这里两种情况不同当且仅当有任意一位同学在任意一门课上获得的分数不同。你不需要像 D 神那么厉害,你只需要计算出情况数模 $10^9 + 7$ 的余数就可以了。

    算法标签:DP,拉格朗日插值

    思路:

    暂时咕着

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=105,p=1e9+7;
    int x[N],ll[N],rr[N];
    int f[N][N],n,m,st,h[N],rk[N],g[N],c[N][N],ny[N],op;
    il int read(){
        int x,f=1;char ch;
        _(!)ch=='-'?f=-1:f;x=ch^48;
        _()x=(x<<1)+(x<<3)+(ch^48);
        return f*x;
    }
    il int mu(int x,int y){
        if(x+y>=p)return x+y-p;
        return x+y;
    }
    il int ksm(LL a,int y){
        LL b=1;
        while(y){
            if(y&1)b=b*a%p;
            a=a*a%p;y>>=1;
        }
        return b;
    }
    il int lag(int u,int r){
        for(int i=1;i<=n+1;i++){
            x[i]=mu(x[i-1],1ll*ksm(i,n-r)*ksm(u-i,r-1)%p);
            if(i==u)return x[i];
        }
        ll[0]=rr[n+2]=1;
        int ans=0,res;
        for(int i=1;i<=n+1;i++)ll[i]=1ll*ll[i-1]*(u-i)%p;
        for(int i=n+1;i;i--)rr[i]=1ll*rr[i+1]*(u-i)%p;
        for(int i=1;i<=n+1;i++){
            res=1ll*ll[i-1]*rr[i+1]%p*x[i]%p*ny[n+1-i]%p*ny[i-1]%p;
            if((n+1-i)&1)ans=mu(ans,p-res);
            else ans=mu(ans,res);
        }
        return ans;
    }
    int main()
    {
        n=read();m=read();st=read();
        for(int i=1;i<=m;i++)h[i]=read();
        for(int i=1;i<=m;i++)rk[i]=read();
        ny[0]=ny[1]=1;
        for(int i=2;i<=n+1;i++)ny[i]=p-1ll*(p/i)*ny[p%i]%p;
        for(int i=1;i<=n+1;i++)ny[i]=1ll*ny[i-1]*ny[i]%p;
        for(int i=0;i<=n;i++){
            c[i][0]=1;
            for(int j=1;j<=n;j++)c[i][j]=mu(c[i-1][j-1],c[i-1][j]);
        }
        for(int i=1;i<=m;i++)g[i]=lag(h[i],rk[i]);
        f[0][n-1]=1;
        for(int i=1;i<=m;i++){
            for(int j=st;j<n;j++){
                for(int k=j;k<=min(n,j+rk[i]-1);k++){
                    f[i][j]=mu(f[i][j],f[i-1][k]*c[k][j]%p*c[n-k-1][n-j-rk[i]]%p);
                }
            }
        }
        int ans=f[m][st];
        for(int i=1;i<=m;i++)ans=1ll*ans*g[i]%p;
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    二分查找改遍
    条件运算符?:
    k倍区间
    分巧克力
    mm
    素数
    递归return
    确定一个域名使用的邮箱服务商
    mysql 存储过程一实例
    使用vmware 共享 windows下的文件夹 到 centos
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10488256.html
Copyright © 2011-2022 走看看