P3533 [JZOJ/NOIP] 火柴排队

给你两个序列 \(a\{\},b\{\}\),求 \(\sum (a_i-b_i)^2\) 的最小值。

可知:

\[\sum(a_i-b_i)^2=\sum {a_i}^2+{b_i}^2-2 \times \sum a_i \times b_i \]

然后我们可以知道,让这个东西最小,就必须让 \(\sum a_i \times b_i\) 最大。同时,我们可以随便列一个方程可知当 \(a_i\)\(b_i\) 最接近的时候是最大的。

至此。

Const
    total=100010;
var
    num,place:array[-1..total*2,1..2] of int64;
    ans:array[-1..total*2] of longint;
    tree:array[-1..total*5] of int64;
    n,an,find:int64;
    i:longint;

procedure Query(l,r,k:longint);
var mid:longint;
begin
    if (1<=l)and(r<=ans[i]) then begin inc(find,tree[k]); exit; end;
    mid:=(l+r) >> 1;
    if 1<=mid then Query(l,mid,k << 1);
    if ans[i]>mid then Query(mid+1,r,k << 1+1);
end;

procedure Change(l,r,k:longint);
var mid:longint;
begin
    if l=r then begin inc(tree[k]); exit; end;
    mid:=(l+r) >> 1;
    if ans[i]<=mid then Change(l,mid,k << 1) else Change(mid+1,r,k << 1+1);
    tree[k]:=tree[k << 1]+tree[k << 1+1];
end;

procedure Sort(l,r,kind:longint);
var 
	s,i,j:longint;
	t:int64;
begin
    i:=l; j:=r; s:=num[(l+r) >> 1,kind];
    repeat
        while num[i,kind]<s do i:=i+1;
        while num[j,kind]>s do j:=j-1;
        if i<=j then
        begin
            t:=num[i,kind]; num[i,kind]:=num[j,kind]; num[j,kind]:=t;
            t:=place[i,kind]; place[i,kind]:=place[j,kind]; place[j,kind]:=t;
            inc(i); dec(j);
         end;
    until i>=j;
    if i<r then Sort(i,r,kind);
    if j>l then Sort(l,j,kind);
end;

begin
    read(n); an:=0;
    for i:=1 to n do begin read(num[i,1]); place[i,1]:=i; end;
    for i:=1 to n do begin read(num[i,2]); place[i,2]:=i; end;
    Sort(1,n,1); Sort(1,n,2);
    for i:=1 to n do ans[place[i,2]]:=place[i,1]; 
    i:=n; Change(1,n,1);
    for i:=n-1 downto 1 do
    begin
        find:=0; Query(1,n,1); inc(an,find);
        Change(1,n,1); an:=an mod 99999997;
    end;
    writeln(an);
end.
posted @ 2019-04-09 12:47  Rattry  阅读(125)  评论(0)    收藏  举报