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 }

猜你喜欢

转载自www.cnblogs.com/changer-qyz/p/10463104.html