【NOIP2017提高组模拟12.17】向再见说再见

题目

【NOIP2017提高组模拟12.17】向再见说再见_第1张图片
Input
【NOIP2017提高组模拟12.17】向再见说再见_第2张图片
Sample Input

4 2
5 35 15 45
40 20 10 30
Output
这里写图片描述
Sample Output

8
Data Constraint
【NOIP2017提高组模拟12.17】向再见说再见_第3张图片

题解

我们可以先分别把a,b都排一下序,然后设p[i]表示比a[i]小的b数组中的数的个数,在排序之后这个东西显然可以线性时间求出
然后我们设f[i,j]表示当前已经做完了前i个人,现在对于A队的i个人每个人有两种情况
1:这个人已经选择了击败B队里的一个人
2:这个人没有选择对手
由于A中的人的能力值是单调上升的,那么显然有
f[i,j]=f[i1,j1]+f[i1,j](p[i]j+1)

然后我们设g[i]表示A队中至少有i个人获胜的情况数,那么根据定义,有
g[i]=f[n,i](ni)! ,因为有n-i个人还没有选择对手嘛,而且我们随便给他们找个对手都是可以的
最后我们可以设h[i]表示A队中有i个人获胜的方案数,那么有
h[i]=g[i]j=i+1nh[j]Cij
其中使用组合数的原因是对于每一个从有j个人赢到有i个人赢的方案都可以产生贡献
然后需要注意的是n,k同奇偶时才有解,然后k=0时注意不要重复统计答案了

贴代码

const
    md=1000000007;
var
    f:array[-1..2005,-1..2005]of int64;
    g,h,a,b,p,cc:array[0..2005]of int64;
    i,j,k,l,m,n:longint;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2];
    repeat
        while a[i]do inc(i);
        while a[j]>mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if lthen qsort(l,j);
    if ithen qsort(i,r);
end;
procedure qsort1(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=b[(i+j) div 2];
    repeat
        while b[i]do inc(i);
        while b[j]>mid do dec(j);
        if i<=j then
        begin
            b[0]:=b[i];
            b[i]:=b[j];
            b[j]:=b[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if lthen qsort1(l,j);
    if ithen qsort1(i,r);
end;
function quickmi(x,y:int64):int64;
var
    a,b,p:int64;
begin
    x:=x mod md;
    a:=1;
    b:=x;
    while y>0 do
    begin
        if y mod 2=1 then a:=(a*b) mod md;
        y:=y div 2;
        b:=(b*b) mod md;
    end;
    exit(a);
end;
begin
    //assign(input,'t3.in'); reset(input);
    readln(n,k);
    if (n mod 2)<>(k mod 2) then
    begin
        writeln(0);
        halt;
    end;
    for i:=1 to n do read(a[i]);
    readln;
    for i:=1 to n do read(b[i]);
    readln;
    qsort(1,n);
    qsort1(1,n);
    b[n+1]:=maxlongint;
    for i:=1 to n do
    begin
        p[i]:=p[i-1];
        while a[i]>b[p[i]+1] do inc(p[i]);
    end;
    f[0,0]:=1;
    for i:=1 to n do
        for j:=0 to i do f[i,j]:=(f[i-1,j]+f[i-1,j-1]*(p[i]-j+1)) mod md;
    cc[0]:=1;
    cc[1]:=1;
    for i:=2 to n do cc[i]:=(cc[i-1]*i) mod md;
    for i:=0 to n do g[i]:=(f[n,i]*cc[n-i]) mod md;
    for i:=n downto 0 do
    begin
        h[i]:=g[i];
        for j:=i+1 to n do h[i]:=(md+h[i]-
        (h[j]*
        ((quickmi(cc[i]*cc[j-i],md-2)*cc[j]) mod md)) mod md) mod md;
    end;
    if k=0 then writeln(h[n div 2]) else
    writeln((h[(k+n) div 2]+h[(n-k) div 2]) mod md);
    //close(input);
end.

你可能感兴趣的:(DP,倍增求lca)