4559: [JLoi2016]成绩比较
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 153 Solved: 100
[ Submit][ Status][ Discuss]
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
2 2
1 2
Sample Output
10
HINT
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N = 105;
typedef long long LL;
const LL mo = 1000000007;
int n,m,k,Max[N],Rank[N],C[N][N],f[N][N],g[N];
inline int Mul(const LL &x,const LL &y) {return x * y % mo;}
inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}
inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}
inline int ksm(int x,int y)
{
int ret = 1;
for (; y; y >>= 1)
{
if (y & 1) ret = Mul(ret,x);
x = Mul(x,x);
}
return ret;
}
inline int Calc(int U,int R)
{
memset(g,0,sizeof(g));
for (int i = 1; i < N; i++)
for (int j = 1; j <= i; j++)
g[i] = Add(g[i],Mul(ksm(j,n - R),ksm(i - j,R - 1)));
int ret = 0;
for (int i = 1; i < N; i++)
{
int A = g[i],B = 1;
for (int j = 1; j < N; j++)
{
if (i == j) continue;
A = Mul(A,Dec(U,j)); B = Mul(B,Dec(i,j));
}
ret = Add(ret,Mul(A,ksm(B,mo - 2)));
}
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m >> k; C[0][0] = f[0][n - 1] = 1;
for (int i = 1; i <= n; i++)
{
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = Add(C[i - 1][j],C[i - 1][j - 1]);
}
for (int i = 1; i <= m; i++) scanf("%d",&Max[i]);
for (int i = 1; i <= m; i++) scanf("%d",&Rank[i]);
for (int i = 1; i <= m; i++)
{
int h = Calc(Max[i],Rank[i]);
for (int j = k; j <= n - 1; j++)
for (int t = j; t <= n - 1; t++)
{
if (t - j > Rank[i] - 1) break;
int now = Mul(C[t][t - j],C[n - 1 - t][Rank[i] - 1 - t + j]);
f[i][j] = Add(f[i][j],Mul(now,Mul(f[i - 1][t],h)));
}
}
cout << f[m][k] << endl;
return 0;
}