4559: [JLoi2016]成绩比较
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 261 Solved: 165
[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
Sample Output
10
HINT
Source
容斥+拉格朗日插值法
讲一个性质:
对于n阶等差数列 (如 1^5,2^5,3^5,4^5….被称为5阶等差)
它们的前n项和可以用一个最高次为n+1次的多项式表示
它们的通项公式可以用一个最高次为n次的多项式表示
因此,我们可以用拉格朗日插值法来优化一些多项式计算
(其实我不是很懂)
推荐blog
http://www.cnblogs.com/zj75211/p/8029303.html
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 105 #define _ %mod #define filein(x) freopen(#x".in","r",stdin); #define fileout(x) freopen(#x".out","w",stdout); using namespace std; const int mod=1000000007; int dp[MAXN],U[MAXN],R[MAXN],C[MAXN][MAXN],Y[MAXN],inv[MAXN]; int N,M,K,ANS; int pow(int a,int b){ int now=1; while(b){ if(b&1) now=(1ll*now*a)_; a=(1ll*a*a)_; b>>=1; } return now; } int Lagrange(int u,int r){ static int lpi[MAXN],rpi[MAXN],p[MAXN],ans,tmp; lpi[0]=1; rpi[N+2]=1; ans=0; for(int i=1;i<=N+1;i++){ p[i]=(1ll*p[i-1]+1ll*pow(i,N-r)*pow(u-i,r-1)_)_; if(i==u) return p[i]; } for(int i=1;i<=N+1;i++) lpi[i]=1ll*lpi[i-1]*(u-i)_; for(int i=N+1;i>=1;i--) rpi[i]=1ll*rpi[i+1]*(u-i)_; for(int i=1;tmp=1,i<=N+1;i++){ tmp=1ll*tmp*lpi[i-1]_*rpi[i+1]_*inv[i-1]_*inv[N+1-i]_*p[i]_; tmp=(1ll*tmp*((N+1-i)&1?-1:1)+mod)_; ans=(1ll*ans+tmp)_; } return ans; } int main() { scanf("%d%d%d",&N,&M,&K); inv[0]=1; inv[1]=1; for(int i=2;i<=N+1;i++) inv[i]=((-1ll*(mod/i)*inv[mod%i])_+mod)_; for(int i=1;i<=N+1;i++) inv[i]=1ll*inv[i]*inv[i-1]_; for(int i=1;i<=M;i++) scanf("%d",&U[i]); for(int i=1;i<=M;i++) scanf("%d",&R[i]); for(int i=0;i<=N;i++){ C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=(1ll*C[i-1][j-1]+C[i-1][j])_; } for(int i=1;i<=M;i++) Y[i]=Lagrange(U[i],R[i]); for(int i=N-1;i>=K;i--) { dp[i]=C[N-1][i]; for(int j=1;j<=M;j++) dp[i]=1ll*dp[i]*C[N-i-1][N-R[j]-i]_; ANS=(1ll*ANS+(((i^K)&1)?-1:1)*1ll*dp[i]*C[i][K]_+mod)_; } for(int i=1;i<=M;i++) ANS=1ll*ANS*Y[i]_; printf("%d",(ANS+mod)_); return 0; }