BZOJ 4559: [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

分析

首先,运用一发容斥原理,求出所有人与B神每门课分数相对关系的不同方案数。

这个似乎大(wo)家(lan)都(de)会(hui)了(yi),我就不说了,详见代码里的f。

然后,我们就需要计算每门课每个人的分数的方案数。对于每一门课,我们分别计算,然后把它们乘起来。

方便起见,令总分为s,名次为rk。

设B神的分数为x,则方案数为x^(n-rk)*(s-x)^(rk-1)

展开得到c(rk-1,0)*s^(rk-1)*x^(n-rk)-c(rk-1,1)*s^(rk-2)*x^(n-rk+1)+c(rk-1,2)*s^(rk-3)*x^(n-rk+2)-……..

显然,我们需要对于x=1..s的所有情况求和。

我们把x次数相同的项放在一起,进行一波整理,问题就转化成了求1^k+2^k+…+s^k

我们设g(k)=1^k+2^k+…+s^k,我们列出一波式子然后观察:

(s+1)^k-s^k=c(k,1)*s^(k-1) +c(k,2)*s^(k-2) +…+c(k,k)*s^0

s^k-(s-1)^k=c(k,1)(s-1)^(k-1)+c(k,2)(s-1)^(k-2)+…+c(k,k)*(s-1)^0

………………………………………………………………………………………………

  2^k-1^k=c(k,1)*1^(k-1)     +c(k,2)*1^(k-2)     +...+c(k,k)*1^0

把这些式子全部相加,得到:

(s+1)^k-1=c(k,1)*g(k-1)+c(k,2)*g(k-2)+…+c(k,k)*g(0)

于是就可以通过递推的方式求出g

然后就做完了。

代码

#include <bits/stdc++.h>

typedef long long LL;

const int N = 105;
const int MOD = 1e9 + 7;

int n,m,k,jc[N],ny[N],po1[N],po2[N],f[N],u[N],r[N],g[N];

int ksm(int x,int y)
{
    int ans = 1;
    while (y)
    {
        if (y & 1) 
            ans = 1ll * ans * x % MOD;
        x = 1ll * x * x % MOD;
        y >>= 1;
    }
    return ans;
}

int C(int n,int m)
{
    if (n < m) 
        return 0;
    return 1ll * jc[n] * ny[m] % MOD * ny[n - m] % MOD;
}

int calc(int u,int r)
{
    for (int i = 0; i <= n + 1; i++) 
        po1[i] = ksm(i,r - 1), po2[i] = ksm(i,n - r);
    for (int i = 1; i <= n + 1; i++)
    {
        f[i] = 0;
        for (int j = 1; j <= i; j++)
            (f[i] += 1ll * po1[i - j] * po2[j] % MOD) %= MOD;
    }
    int ans = 0;
    for (int i = 1; i <= n + 1; i++)
    {
        int s1 = f[i], s2 = 1;
        for (int j = 1; j <= n + 1; j++)
            if (i != j) 
                s1 = 1ll * s1 * (u - j) % MOD, s2 = 1ll * s2 * (i - j) % MOD;
        (ans += 1ll * s1 * ksm(s2, MOD - 2) % MOD) %= MOD;
    }
    return ans;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i = 1; i <= m; i++) 
        scanf("%d",&u[i]);
    for (int i = 1; i <= m; i++) 
        scanf("%d",&r[i]);
    jc[0] = jc[1] = ny[0] = ny[1] = 1;
    for (int i = 2; i <= n; i++) 
        jc[i] = 1ll * jc[i - 1] * i % MOD, ny[i] = 1ll * (MOD - MOD / i) * ny[MOD % i] % MOD;
    for (int i = 2; i <= n; i++) 
        ny[i] = 1ll * ny[i] * ny[i - 1] % MOD;
    for (int i = 1; i <= m; i++) 
        g[i] = calc(u[i],r[i]);
    int ans = 0;
    for (int i = k; i < n; i++)
    {
        int w = 1ll * C(n - 1, i) * C(i, k) % MOD;
        for (int j = 1; j <= m; j++) 
            w = 1ll * w * C(n - i - 1, r[j] - 1) % MOD * g[j] % MOD;
        if ((i - k) & 1) 
            (ans -= w) %= MOD;
        else (ans += w) %= MOD;
    }
    printf("%d",(ans + MOD) % MOD);
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ypxrain/article/details/79966577
上一篇AtCoder Grand Contest 012 C - Tautonym Puzzle
下一篇AtCoder Grand Contest 016 C - +/- Rectangle
想对作者说点什么? 我来说一句

BZOJ题目镜像

2014年09月14日 15.01MB 下载

bzoj FFT 的模版

2011年12月20日 3KB 下载

BZOJ全代码

2018年02月05日 489KB 下载

BZOJ泡泡堂题解.doc

2016年09月29日 15KB 下载

WJMZBMR的代码们

2016年05月24日 21.32MB 下载

BZOJ第一部分

2017年11月03日 79.13MB 下载

BZOJ第四部分

2017年11月04日 28.38MB 下载

BZOJ第二部分

2017年11月04日 74.15MB 下载

BZOJ第三部分

2017年11月04日 74.83MB 下载

双回文子串的相关解法

2012年03月20日 12KB 下载

没有更多推荐了,返回首页

关闭
关闭