莫队乱搞--BZOJ2038: [2009国家集训队]小Z的袜子(hose)

$n \leq 50000$的$\leq 50000$的数字序列,$m \leq 50000$个询问,每次问一个区间中随机拿两次(不放回)拿到相同数字的概率,以既约分数形式输出。

莫队入门。把询问按“同块排$r$、不同块排$l$”的顺序,依靠左右端点两个指针跑来跑去依次回答。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 //#include<queue>
 6 //#include<time.h>
 7 //#include<complex>
 8 #include<algorithm>
 9 #include<stdlib.h>
10 using namespace std;
11 
12 int n,m,lq,tot;
13 #define maxn 50011
14 #define maxm 255
15 int bel[maxn],a[maxn],cnt[maxn];
16 struct Ques{int l,r,id;}q[maxn];
17 bool cmp(const Ques a,const Ques b) {return bel[a.l]==bel[b.l]?a.r<b.r:a.l<b.l;}
18 
19 #define LL long long
20 LL ss;
21 struct Ans{LL a,b;}ans[maxn];
22 LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
23 void modify(int p,int type) {ss-=(LL)cnt[a[p]]*cnt[a[p]]; cnt[a[p]]+=type; ss+=(LL)cnt[a[p]]*cnt[a[p]];}
24 
25 int main()
26 {
27     scanf("%d%d",&n,&lq);
28     m=233; for (int i=1;i<=n;i++) bel[i]=(i-1)/m+1; tot=bel[n];
29     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
30     for (int i=1;i<=lq;i++) scanf("%d%d",&q[i].l,&q[q[i].id=i].r);
31     sort(q+1,q+1+lq,cmp);
32     
33     int L=1,R=0; ss=0;
34     for (int i=1;i<=lq;i++)
35     {
36         while (L<q[i].l) modify(L,-1),L++;
37         while (L>q[i].l) modify(L-1,1),L--;
38         while (R<q[i].r) modify(R+1,1),R++;
39         while (R>q[i].r) modify(R,-1),R--;
40         Ans &now=ans[q[i].id];
41         now.a=ss-(q[i].r-q[i].l+1);
42         now.b=(q[i].r-q[i].l)*1ll*(q[i].r-q[i].l+1);
43         LL g=gcd(now.a,now.b); now.a/=g; now.b/=g;
44     }
45     
46     for (int i=1;i<=lq;i++) printf("%lld/%lld\n",ans[i].a,ans[i].b);
47     return 0;
48 }
View Code

 

posted @ 2018-03-15 08:21  Blue233333  阅读(196)  评论(0编辑  收藏  举报