标签:动态规划 printf code 容斥 nbsp main led using 相关
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
首先发现对于n个确定排名的人,分数和其排名无关,这里可以分开处理。
有两种做法,第一种我分成三个集合,1:我 2:分数小于等于我的3:分数大于等于我的。
设f[i]表示完虐至少i人,三个集合内无名次顺序的方案数,可以发现容斥是能很好地解决这个分问题的。
转移是f[i]=C(n-1,i)*Σj=1,j<=mC(n-i-1,r[j]-1)-Σj=i+1,j<=nf[j]*C(j,i) 这个很容易推得。
然后发现每门的得分情况互不相关,符合乘法原理,我们分开处理,设当前科目排名r,得分上限u,我的得分是x。方案数是 xn-r(u-x)r-1 但是u太大了,x的取值是[1,u],不可能枚举得来,还得分析。
设t[x]=xn-r(u-x)r-1
=xn-r *(C(r-1,r-1)*ur-1-C(r-1,r-2)*ur-2*x+……+C(r-1,0)*xr-1)
=C(r-1,r-1)*ur-1*xn-r-C(r-1,r-2)*ur-2*xn-r+1+……+C(r-1,0)*xn-1
x=1:请自动脑补
x=2:请自动脑补
x=3:请自动脑补
……
x=u:请自动脑补
设g[k]=1k+2k+3k+……+uk
Σx=1,x<=ut[x]=C(r-1,r-1)*ur-1*g[n-r]-C(r-1,r-2)*ur-2*xn-r+1*g[n-r+1]+……+C(r-1,0)*xn-1*g[n-1]
现在只要知道如何求g[k],考虑递推。
发现设p[a+1]=(a+1)k=C(k,k)*ak+C(k,k-1)*ak-1+……+C(k,0)*a0
Σa=1,a<=up[a+1]=g[k]+(u+1)k-1=C(k,k)*g[k]+C(k,k-1)*g[k-1]+……+C(k,0)*g[0]
可以由 (u+1)k-1=C(k,k-1)*g[k-1]+……+C(k,0)*g[0]
移项得 g[k-1]=(u+1)k-1-(C(k,k-2)*g[k-2]+C[k,k-3]*g[k-3]+……+C[k,0]*g[0])
用k=k+1替入得:g[k]=(u+1)k+1-1-(C(k+1,k-1)*g[k-1]+C[k+1,k-2]*g[k-2]+……+C[k+1,0]*g[0])
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 using namespace std;
5 const int N=110,Mod=1000000007;
6 int n,m,K,u[N],r[N];
7 typedef long long LL;
8 LL fac[N],ifac[N],c[N][N],f[N],g[N];
9 LL Inv(LL x){return x==1?1:(Mod-Mod/x)*Inv(Mod%x)%Mod;}
10 LL C(int x,int y){
11 if(x<y||x<0||y<0)return 0;
12 return fac[x]*ifac[y]%Mod*ifac[x-y]%Mod;
13 }
14
15 LL Quick_pow(LL x,LL y){
16 LL ret=1;
17 while(y){
18 if(y&1)ret=ret*x%Mod;
19 y>>=1;x=x*x%Mod;
20 }
21 return ret;
22 }
23
24 int main(){
25 scanf("%d%d%d",&n,&m,&K);
26 for(int i=1;i<=m;i++)
27 scanf("%d",&u[i]);
28 for(int i=1;i<=m;i++)
29 scanf("%d",&r[i]);
30 fac[0]=ifac[0]=1;
31 for(int i=1;i<N;i++){
32 fac[i]=fac[i-1]*i%Mod;
33 ifac[i]=Inv(fac[i]);
34 }
35 for(int i=n-1;i>=K;i--){
36 f[i]=C(n-1,i);
37 for(int j=1;j<=m;j++)
38 (f[i]*=C(n-i-1,r[j]-1))%=Mod;
39 for(int j=i+1;j<n;j++){
40 (f[i]-=f[j]*C(j,i))%=Mod;
41 (f[i]+=Mod)%=Mod;
42 }
43 }
44 LL ans=f[K];
45 for(int i=1;i<=m;i++){
46 LL R=r[i],U=u[i];
47 g[0]=U;
48 for(int k=1;k<=n;k++){
49 g[k]=Quick_pow(U+1,k+1)-1;
50 for(int j=k-1;j>=0;j--)
51 (g[k]+=Mod-C(k+1,j)*g[j]%Mod)%=Mod;
52 (g[k]*=Inv(C(k+1,k)))%=Mod;
53 }
54 LL tmp=0,rmp;
55 for(int j=1,s=1;j<=R;s*=-1,j++){
56 rmp=(s+Mod)*C(R-1,j-1)%Mod;
57 (rmp*=Quick_pow(U,R-j))%=Mod;
58 (rmp*=g[n-R+j-1])%=Mod;
59 (tmp+=rmp)%=Mod;
60 }
61 ans=ans*tmp%Mod;
62 }
63 printf("%lld\n",ans);
64 return 0;
65 }
动态规划(计数DP):JLOI 2016 成绩比较
标签:动态规划 printf code 容斥 nbsp main led using 相关
原文地址:http://www.cnblogs.com/TenderRun/p/6005744.html