bzoj2038小Z的袜子(hose)(莫队)
作者:互联网
传送:https://www.lydsy.com/JudgeOnline/problem.php?id=2038
题意:有n个袜子,每个袜子有一个颜色。m个询问,询问在一个区间$[l,r]$内,选择两个相同颜色袜子的概率。
分析:莫队。将询问排序。每次转移时,$cnt$先减去$num[tmp]*num[tmp]$,更新后,再加上$num[tmp]*num[tmp]$。最后的答案就是$cnt-b[i].len$/$b[i].len*(b[i].len-1)$。
1 #include<bits/stdc++.h>
2 using namespace std; 3 typedef long long ll; 4 const int maxn=5e4+10; 5 struct node{ 6 int l,r,blo,id; 7 bool operator <(node p)const{ 8 return blo<p.blo || blo==p.blo && r<p.r; 9 } 10 }b[maxn]; 11 struct node2{ 12 ll a,b; 13 }ans[maxn]; 14 int a[maxn]; 15 ll num[maxn]; 16 int ll_,rr_,block; 17 ll cnt; 18 void add(int x){ 19 int tmp=a[x]; 20 cnt-=num[tmp]*num[tmp]; 21 num[tmp]++; 22 cnt+=num[tmp]*num[tmp]; 23 } 24 void del(int x){ 25 int tmp=a[x]; 26 cnt-=num[tmp]*num[tmp]; 27 num[tmp]--; 28 cnt+=num[tmp]*num[tmp]; 29 } 30 ll calc(node p){ 31 return 1ll*(p.r-p.l+1)*(p.r-p.l); 32 } 33 ll gcd_(ll x,ll y){ 34 if (y==0) return x; 35 else return gcd_(y,x%y); 36 } 37 int main(){ 38 int n,m; scanf("%d%d",&n,&m); 39 block=sqrt(n); 40 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 41 for (int i=0;i<m;i++){ 42 scanf("%d%d",&b[i].l,&b[i].r); 43 b[i].blo=b[i].l/block; 44 b[i].id=i; 45 } 46 sort(b,b+m); 47 ll_=1,rr_=0,cnt=0; 48 memset(num,0,sizeof(num)); 49 for (int i=0;i<m;i++){ 50 while (ll_<b[i].l) del(ll_++); 51 while (ll_>b[i].l) add(--ll_); 52 while (rr_<b[i].r) add(++rr_); 53 while (rr_>b[i].r) del(rr_--); 54 ans[b[i].id].a=cnt-(b[i].r-b[i].l+1); 55 ans[b[i].id].b=calc(b[i]); 56 } 57 for (int i=0;i<m;i++){ 58 ll tmp=gcd_(ans[i].a,ans[i].b); 59 ans[i].a/=tmp; ans[i].b/=tmp; 60 if (ans[i].a==0) printf("0/1\n"); 61 else printf("%lld/%lld\n",ans[i].a,ans[i].b); 62 } 63 return 0; 64 }
标签:tmp,cnt,hose,袜子,len,num,bzoj2038,莫队,id 来源: https://www.cnblogs.com/changer-qyz/p/10463104.html