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);
}