给出n个数字,m次询问,每次询问在区间[li,ri]之间任选两个数字相等的概率是多少。(n,q<=50000)
在区间[l,r]中概率是:
考虑分子,
因为C(2,x)=x2−x2C(2,x)=x2−x2,
所以分子=∑vi=1f(i)2−∑vi=1f(i)2
显然,∑f(i)=r−l+1(1<=i<=v)
区间[l,r+1]与区间[l,r]相比只多了一个元素z,
前式中分子的值S=S0-f(z)^2+(f(z)+1)^2-1=S0+2*f(z),同时inc(f(z)),O(1)的。
莫队算法优化:
注意到,每个区间可以抽象成平面中的点,每次转移的花费都相当与从某点到另一点的曼哈顿距离的长度。
所以我们花费的便是这些平面中的点联通的曼哈顿距离。平面点的曼哈顿最小生成树!
但是实际来说,搞定一个manhattan mst需要的时间不小,
神犇曰:分块是个好东西
确实,利用分块,我们可以实现O(nn√)的时间复杂度。
1):排序,以左段点所在的块为第一关键字,以右端点为第二关键字
2):从左往右处理询问(离线)
3):不断调整l,r的位置并同时修改
type
rec=record
l,r,num,t:longint;
end;
var
n,m,len,now :longint;
i,j :longint;
a :array[0..50010] of rec;
c,size :array[0..50010] of int64;
col,ans :array[0..50010] of int64;
tt,all :int64;
procedure swap(var a,b:longint);
var
c:longint;
begin
c:=a; a:=b; b:=c;
end;
function gcd(a,b:int64):int64;
begin
if ax) or ((a[j].num=x) and (a[j].r>y)) do dec(j);
if (i<=j) then
begin
z:=a[i];a[i]:=a[j];a[j]:=z;
inc(i);dec(j);
end;
end;
if (il) then sort(l,j);
end;
begin
read(n,m);
for i:=1 to n do read(c[i]);
len:=trunc(sqrt(m));
for i:=1 to m do
begin
read(a[i].l,a[i].r);
if (a[i].l>a[i].r) then swap(a[i].l,a[i].r);
size[i]:=a[i].r-a[i].l+1;
a[i].t:=i;
a[i].num:=a[i].l div len+1;
end;
sort(1,m);
//
i:=1;
while (i<=m) do
begin
now:=a[i].num;
fillchar(col,sizeof(col),0);
for j:=a[i].l to a[i].r do
begin
inc(ans[a[i].t],2*col[c[j]]);
inc(col[c[j]]);
end;
inc(i);
while (a[i].num<=now) and (i<=m) do
begin
ans[a[i].t]:=ans[a[i-1].t];
for j:=a[i-1].r+1 to a[i].r do
begin
inc(ans[a[i].t],2*col[c[j]]);
inc(col[c[j]]);
end;
if (a[i-1].l
——by Eirlys