【BZOJ4559】成绩比较(组合计数,容斥原理)

题意:

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的余数就可以了。
N<=100,M<=100,Ui<=10^9
 
思路:WYZ作业
事实上约大爷day1前就已秒掉此题,果然连ZJ女队队长也比不了……
只能%一发题解,这就是数学题弱者的无奈……
From http://blog.csdn.net/aarongzk/article/details/51760818

整体思路:先求出所有其他人和B神每门课分数相对大小的不同方案数,然后再计算每门课的方案数,两者乘积即为答案。

① 先算第一部分,直接算比较难,考虑容斥原理。

f[i]表示有i个人被碾压的方案数,则f[i]=C(n-1,i)*C(n-1-i,rnk[1]-1)*C(n-1-i,rnk[2]-1)*…*C(n-1-i,rnk[m]-1)-f[i+1]*C(i+1,i)-f[i+2]*C(i+2,i)-…-f[n-1]*C(n-1,i),即用至少i个人被碾压的方案数减去不合法的。f数组逆向递推即可求出。

 

② 再算第二部分,对于每一门分别计算,然后乘起来。

假设某一门课的总分为s,B神的名次和分数分别为rnk和x,则方案数为x^(n-rnk)*(s-x)^(rnk-1)。

展开化简得∑ C(rnk-1,i)*s^(rnk-1-i)*x^(n-rnk+i),0≤i≤rnk-1。

我们要对x=1,2,…,s的所有情况求和。

把x次数相同的项放在一起,转化成求1^p+2^p+...+s^p,p为常数。

设g[i]=1^i+2^i+...+s^i,然后观察规律:

(s+1)^(p+1)-s^(p+1)=C(p+1,0)*s^0+C(p+1,1)*s^1+…+C(p+1,p)*s^p

s^(p+1)-(s-1)^(p+1)=C(p+1,0)*(s-1)^0+C(p+1,1)*(s-1)^1+…+C(p+1,p)*(s-1)^p

……

2^(p+1)-1^(p+1)=C(p+1,0)*1^0+C(p+1,1)*1^1+…+C(p+1,p)*1^p

将式子相加,得:(s+1)^(p+1)-1=C(p+1,0)*g[0]+C(p+1,1)*g[1]+…+C(p+1,p)*g[p]

移项,得:g[p]=((s+1)^(p+1)-1-C(p+1,0)*g[0]-C(p+1,1)*g[1]-…-C(p+1,p-1)*g[p-1]) / C(p+1,p)

于是可以通过正向递推求出g数组。

这样,这个问题就完美解决了,时间复杂度O(n^3)。

 1 const mo=1000000007;
 2 var exf,fac:array[0..1000]of int64;
 3     a,b:array[1..1000]of longint;
 4     g,f:array[0..1000]of int64;
 5     n,m,k1,i,j,k,v:longint;
 6     ans,tmp:int64;
 7 
 8 function c(n,m:longint):int64;
 9 begin
10  if n<m then exit(0);
11  exit(fac[n]*exf[m] mod mo*exf[n-m] mod mo);
12 end;
13 
14 function mult(x,y:longint):int64;
15 var tmp:int64;
16 begin
17  if x=0 then exit(0);
18  mult:=1; tmp:=x;
19  while y>0 do
20  begin
21   if y and 1=1 then mult:=mult*tmp mod mo;
22   tmp:=tmp*tmp mod mo;
23   y:=y>>1;
24  end;
25 end;
26 
27 begin
28  assign(input,'bzoj4559.in'); reset(input);
29  assign(output,'bzoj4559.out'); rewrite(output);
30  readln(n,m,k1);
31  for i:=1 to m do read(a[i]);
32  for i:=1 to m do read(b[i]);
33  exf[0]:=1; exf[1]:=1; fac[0]:=1;
34  for i:=2 to 1000 do exf[i]:=exf[mo mod i]*(mo-mo div i) mod mo;
35  for i:=1 to 1000 do exf[i]:=exf[i-1]*exf[i] mod mo;
36  for i:=1 to 1000 do fac[i]:=fac[i-1]*i mod mo;
37  for i:=n-1 downto k1 do
38  begin
39   f[i]:=c(n-1,i);
40   for j:=1 to m do f[i]:=f[i]*c(n-i-1,b[j]-1) mod mo;
41   for j:=i+1 to n-1 do f[i]:=(f[i]-f[j]*c(j,i) mod mo+mo) mod mo;
42  end;
43 
44  ans:=1;
45  for i:=1 to m do
46  begin
47   g[0]:=a[i];
48   for j:=1 to n do
49   begin
50    g[j]:=(mult(a[i]+1,j+1)-1+mo) mod mo;
51    for k:=0 to j-1 do g[j]:=(g[j]-c(j+1,k)*g[k] mod mo+mo) mod mo;
52    g[j]:=g[j]*mult(j+1,mo-2) mod mo;
53   end;
54   tmp:=0; v:=1;
55   for j:=0 to b[i]-1 do
56   begin
57    tmp:=(tmp+c(b[i]-1,j)*mult(a[i],b[i]-1-j) mod mo*g[n-b[i]+j]*v mod mo+mo) mod mo;
58    v:=-v;
59   end;
60   ans:=ans*tmp mod mo;
61  end;
62  //for i:=1 to n do writeln(g[i]);
63  writeln(ans*f[k1] mod mo);
64 
65  close(input);
66  close(output);
67 end.

 

 

 
 

posted on 2017-03-29 17:17  myx12345  阅读(289)  评论(0编辑  收藏  举报

导航