1. 程式人生 > >4559[JLoi2016]成績比較 容斥+拉格朗日插值法

4559[JLoi2016]成績比較 容斥+拉格朗日插值法

mem otto spa ack input mes mod 只需要 rip

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

4559[JLoi2016]成績比較 容斥+拉格朗日插值法