【BZOJ2038】小Z的袜子(莫队)

题意:

给定n个数a1, a2…… an与m个询问(L,R)。对于每个询问,从aL, aL+1…… aR这R-L+1个数中随机取出两个数,求这两个数相同的概率。

数据范围:1<=n,m,ai<=50000

思路:

以下是原话:

平方运算的存在是线段树无法打破的坚冰!

只有询问,没有修改! 可以任意的顺序求解询问!

 考虑两个位置关系任意的区间[L1,R1]与[L2,R2]

已有前者的信息,要得到后者的信息只需插入或删除L1与L2间的数和R1与R2间的数

若L1<L2则删除[L1,L2-1]内的数, 否则插入[L2,L1-1]内的数;

若R1<R2则插入[R1+1,R2]内的数, 否则删除[R2+1,R1]内的数;

无论何种情况,所需操作数均为 |L1 - L2| + |R1 - R2|

将m个区间重新排列,最小化:

 

定义(L0,R0) = (1,0)

分块,将询问以左端点所在块的编号为第一关键字,右端点大小为第二关键字排序,依次计算保证

时间复杂度O(N^1.5)

复杂度分析是这样的:
1、i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
2、i与i+1跨越一块,r最多变化n,由于有n^0.5块,所以这一部分时间复杂度是n^1.5
3、i与i+1在同一块内时l变化不超过n^0.5,跨越一块也不会超过n^0.5,忽略*2。由于有m次询问(和n同级),所以时间复杂度是n^1.5
于是就是O(n^1.5)了

  1 type arr=record
  2           l,r,c,t:longint;
  3          end;
  4 var s:array[0..50000]of int64;
  5     ans:array[1..50000,1..2]of int64;
  6     q:array[1..50000]of arr;
  7     c,a:array[1..50000]of longint;
  8     n,m,i,kuai:longint;
  9     tmp:int64;
 10 
 11 procedure swap(var x,y:arr);
 12 var t:arr;
 13 begin
 14  t:=x; x:=y; y:=t;
 15 end;
 16 
 17 procedure qsort(l,r:longint);
 18 var i,j,mid1,mid2:longint;
 19 begin
 20  i:=l; j:=r; mid1:=q[(l+r)>>1].c; mid2:=q[(l+r)>>1].r;
 21  repeat
 22   while (mid1>q[i].c)or((mid1=q[i].c)and(mid2>q[i].r)) do inc(i);
 23   while (mid1<q[j].c)or((mid1=q[j].c)and(mid2<q[j].r)) do dec(j);
 24   if i<=j then
 25   begin
 26    swap(q[i],q[j]);
 27    inc(i); dec(j);
 28   end;
 29  until i>j;
 30  if l<j then qsort(l,j);
 31  if i<r then qsort(i,r);
 32 end;
 33 
 34 function gcd(x,y:int64):int64;
 35 var r,t:int64;
 36 begin
 37  if x<y then
 38  begin
 39   t:=x; x:=y; y:=t;
 40  end;
 41  repeat
 42   r:=x mod y;
 43   x:=y;
 44   y:=r;
 45  until r=0;
 46  exit(x);
 47 end;
 48 
 49 procedure add(x,y:longint);
 50 begin
 51  tmp:=tmp-s[a[x]]*s[a[x]];
 52  s[a[x]]:=s[a[x]]+y;
 53  tmp:=tmp+s[a[x]]*s[a[x]];
 54 end;
 55 
 56 procedure modui;
 57 var a,b,c,d,k1,k2,k:int64;
 58     i,j:longint;
 59 begin
 60  a:=1; b:=0; tmp:=0;
 61  for i:=1 to m do
 62  begin
 63   c:=q[i].l; d:=q[i].r;
 64   for j:=b+1 to d do add(j,1);
 65   for j:=c to a-1 do add(j,1);
 66   for j:=a to c-1 do add(j,-1);
 67   for j:=d+1 to b do add(j,-1);
 68   a:=c; b:=d;
 69   if c=d then
 70   begin
 71    ans[i,1]:=0; ans[i,2]:=1;
 72    continue;
 73   end;
 74   k1:=tmp-(d-c+1);
 75   if k1=0 then
 76   begin
 77    ans[i,1]:=0; ans[i,2]:=1;
 78    continue;
 79   end;
 80   k2:=(d-c+1)*(d-c);
 81   k:=gcd(k1,k2);
 82   ans[i,1]:=k1 div k;
 83   ans[i,2]:=k2 div k;
 84  end;
 85 
 86 end;
 87 
 88 procedure qsort1(l,r:longint);
 89 var i,j,mid:longint;
 90     t:int64;
 91 begin
 92  i:=l; j:=r; mid:=q[(l+r)>>1].t;
 93  repeat
 94   while mid>q[i].t do inc(i);
 95   while mid<q[j].t do dec(j);
 96   if i<=j then
 97   begin
 98    swap(q[i],q[j]);
 99    t:=ans[i,1]; ans[i,1]:=ans[j,1]; ans[j,1]:=t;
100    t:=ans[i,2]; ans[i,2]:=ans[j,2]; ans[j,2]:=t;
101    inc(i); dec(j);
102   end;
103  until i>j;
104  if l<j then qsort1(l,j);
105  if i<r then qsort1(i,r);
106 end;
107 
108 begin
109  assign(input,'bzoj2038.in'); reset(input);
110  assign(output,'bzoj2038.out'); rewrite(output);
111  readln(n,m);
112  for i:=1 to n do read(a[i]);
113  kuai:=trunc(sqrt(n));
114  for i:=1 to n do c[i]:=(i-1) div kuai+1;
115  for i:=1 to m do
116  begin
117   readln(q[i].l,q[i].r);
118   q[i].c:=c[q[i].l];
119   q[i].t:=i;
120  end;
121  qsort(1,m);
122  modui;
123  qsort1(1,m);
124  for i:=1 to m do writeln(ans[i,1],'/',ans[i,2]);
125  close(input);
126  close(output);
127 end.

 

posted on 2017-02-28 11:07  myx12345  阅读(131)  评论(0编辑  收藏  举报

导航