【BZOJ4559】成绩比较(组合计数,容斥原理)
题意:
整体思路:先求出所有其他人和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.