zoukankan      html  css  js  c++  java
  • 【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.
     
     
  • 相关阅读:
    ural 1519 fomular 1 既插头DP学习笔记
    2016集训测试赛(十九)Problem C: 无聊的字符串
    2016集训测试赛(十九)Problem A: 24点大师
    2016集训测试赛(二十)Problem B: 字典树
    写一个addEventListener以及removeEventListener
    关于props的注意事项!
    swiper轮播始终居中active图片
    vue中登录模块的插件封装
    v-show
    v-if
  • 原文地址:https://www.cnblogs.com/myx12345/p/6640740.html
Copyright © 2011-2022 走看看