莫队乱搞--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 }