列表

详情


NC20150. [JLOI2016]成绩比较

描述

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神那么厉害,你只需要计算出情况数模10^9+7的余数就可以了。

输入描述

第一行包含三个正整数N,M,K,分别表示G系的同学数量(包括B神),必修课的数量和被B神碾压的同学数量。
第二行包含M个正整数,依次表示每门课的最高分Ui
第三行包含M个正整数,依次表示B神在每门课上的排名Ri。保证1 ≤ Ri ≤ N。
数据保证至少有1种情况使得B神说的话成立。N ≤ 100,M ≤ 100,Ui ≤ 10^9

输出描述

仅一行一个正整数,表示满足条件的情况数模10^9+7的余数。

示例1

输入:

3 2 1 
2 2 
1 2

输出:

10

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 9ms, 内存消耗: 436K, 提交时间: 2022-04-12 10:17:34

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define _for(i, a, b) for (int i = (a); i < (int)(b); ++i)
const int NN = 104, P = 1e9 + 7;
LL pow_m(LL x, int k) {  // xᵏ
  LL r = 1;
  for (x %= P; k; k >>= 1, (x *= x) %= P)
    if (k & 1) (r *= x) %= P;
  return r;
}
int C[NN][NN];
int main() {
  _for(n, 0, NN) {
    C[n][0] = C[n][n] = 1;
    _for(j, 1, n) C[n][j] = (C[n - 1][j] + C[n - 1][j - 1]) % P;
  }
  int N, M, K;
  cin >> N >> M >> K;  
  vector<int> U(M), R(M);
  vector<LL> F(N + 1), G(N + 1);
  for (int& u : U) cin >> u;
  for (int& r : R) cin >> r;
  for (int i = N - 1; i; i--) {
    F[i] = C[N - 1][i];
    _for(j, 0, M)(F[i] *= C[N - i - 1][R[j] - 1]) %= P;
    _for(j, i + 1, N)(F[i] += -F[j] * C[j][i] % P + P) %= P;
  }
  LL Ans = F[K];
  _for(i, 0, M) {
    int u = U[i], r = R[i];
    G[0] = u % P;
    for (int j = 1; j <= N; j++) {
      LL x = 1 - pow_m(u + 1, j + 1);
      _for(k, 0, j)(x += G[k] * C[j + 1][k]) %= P;
      G[j] = x * pow_m(-1 - j, P - 2) % P;
    }
    LL x = 0;
    _for(K, 0, r) {
      LL sign = (r - K - 1) & 1 ? -1 : 1;
      (x += sign * C[r - 1][K] * pow_m(u, K) % P * G[N - K - 1] % P) %= P;
    }
    (Ans *= (x + P) % P) %= P;
  }
  cout << Ans << endl;
  return 0;
}

上一题