bzoj 2038 莫队算法
2017-01-04 17:12
274 查看
给出n个数字,m次询问,每次询问在区间[li,ri]之间任选两个数字相等的概率是多少。(n,q<=50000)
在区间[l,r]中概率是:
∑vi=1C(2,f(i))C(2,r−l+1)∑C(2,f(i))C(2,r−l+1)(1<=i<=v)
(v表示数字值,f(i)表示数字i在区间内出现的次数)
考虑分子,
因为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的位置并同时修改
——by Eirlys
在区间[l,r]中概率是:
∑vi=1C(2,f(i))C(2,r−l+1)∑C(2,f(i))C(2,r−l+1)(1<=i<=v)
(v表示数字值,f(i)表示数字i在区间内出现的次数)
考虑分子,
因为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 a<b then exit(gcd(b,a)) else if (b=0) then exit(a) else exit(gcd(b,a mod b)); end; procedure sort(l,r:longint); var i,j:longint; x,y:longint; z:rec; begin i:=l;j:=r; x:=a[(l+r) div 2].num; y:=a[(l+r) div 2].r; while (i<=j) do begin while (a[i].num<x) or ((a[i].num=x) and (a[i].r<y)) do inc(i); while (a[j].num>x) 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 (i<r) then sort(i,r); if (j>l) 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<a[i].l) then begin for j:=a[i-1].l to a[i].l-1 do begin dec(col[c[j]]); dec(ans[a[i].t],2*col[c[j]]); end; end else begin for j:=a[i].l to a[i-1].l-1 do begin inc(ans[a[i].t],2*col[c[j]]); inc(col[c[j]]); end; end; inc(i); end; end; // for i:=1 to m do begin if size[i]=1 then all:=1 else all:=size[i]*(size[i]-1); tt:=gcd(all,ans[i]); writeln(ans[i] div tt,'/',all div tt); end; end.
——by Eirlys
相关文章推荐
- [BZOJ 2038] 2009国家集训队 小Z的袜子 · 莫队算法
- bzoj 2038 A-小Z的袜子[hose] - 莫队算法
- BZOJ 2038([2009国家集训队]小Z的袜子(hose)-莫队算法序列)
- 莫队算法入门 BZOJ 2038
- 莫队算法 BZOJ 2038 小Z的袜子
- BZOJ 2038 小Z的袜子 莫队算法(模板题)
- BZOJ 2038 小Z的袜子(hose) (莫队算法)
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)(莫队算法)
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 【莫队算法】
- [BZOJ]2038: [2009国家集训队]小Z的袜子(hose) 莫队算法
- BZOJ 2038 2009国家集训队 小Z的袜子 莫队算法
- bzoj 2038 小Z的袜子(hose)(莫队算法)
- bzoj 2038: [2009国家集训队]小Z的袜子(hose)(莫队算法)
- BZOJ_2038 小Z的袜子(莫队算法)
- BZOJ 2038 小Z的袜子(莫队算法)
- BZOJ 2038 小Z的袜子 莫队算法介绍
- BZOJ - 2038 小Z的袜子 莫队算法
- BZOJ 2038 [2009国家集训队] 小Z的袜子 莫队算法
- BZOJ2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- 莫队算法(小Z的袜子,BZOJ 2038)