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

题意

  给出包含n个数字的序列,和m个查询。每次查询问区间[l,r]中挑选出两个数字,大小相同的概率为多少。

分析

  莫队的入门题吧。代码是非常好写,关键是时间复杂度的证明。O(n*sqrt(n))。我还有点迷糊,等我再做几个题再说···

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 
 7 using namespace std;
 8 typedef long long LL;
 9 const int maxn=50000+100;
10 int val[maxn],belong[maxn],f[maxn];
11 int n,m,cnt,block;
12 LL gcd(LL a,LL b){
13     if(!b)return a;
14     return gcd(b,a%b);
15 }
16 
17 struct Node{
18     int L,R,id;
19     bool operator<(const Node& rhs)const{
20         return belong[L]<belong[rhs.L]||(belong[L]==belong[rhs.L]&&R<rhs.R);
21     }
22     LL a,b;
23     void solve(){
24         LL r=gcd(a,b);
25         a/=r,b/=r;
26     }
27 }ask[maxn];
28 int cmp(Node a,Node b){
29     return a.id<b.id;
30 }
31 LL ans;
32 void update(int p,int addv){
33     ans=ans+2*addv*f[val[p]]+1;
34     f[val[p]]+=addv;
35 }
36 
37 int main(){
38     scanf("%d%d",&n,&m);
39     memset(f,0,sizeof(f));
40     for(int i=1;i<=n;i++)
41         scanf("%d",&val[i]);
42     block=sqrt(n);
43     cnt=n/block;
44     if(n%block)cnt++;
45     for(int i=1;i<=n;i++){
46         belong[i]=(i-1)/block+1;
47     }
48     for(int i=1;i<=m;i++){
49         scanf("%d%d",&ask[i].L,&ask[i].R);
50         ask[i].id=i;
51     }
52 
53     sort(ask+1,ask+1+m);
54     ans=0;
55     int l=1,r=0;
56     for(int i=1;i<=m;i++){
57         if(r<ask[i].R){
58             for(r=r+1;r<ask[i].R;r++){
59                 update(r,1);
60             }
61             update(r,1);
62         }
63         if(l>ask[i].L){
64             for(l=l-1;l>ask[i].L;l--){
65                 update(l,1);
66             }
67             update(l,1);
68         }
69         if(r>ask[i].R){
70             for(;r>ask[i].R;r--){
71                 update(r,-1);
72             }
73         }
74         if(l<ask[i].L){
75             for(;l<ask[i].L;l++){
76                 update(l,-1);
77             }
78         }
79         if(ask[i].L==ask[i].R){
80             ask[i].a=0,ask[i].b=1;
81             continue;
82         }
83         ask[i].a=ans-(ask[i].R-ask[i].L+1),ask[i].b=(LL)(ask[i].R-ask[i].L+1)*(ask[i].R-ask[i].L);
84         ask[i].solve();
85     }
86     sort(ask+1,ask+1+m,cmp);
87     for(int i=1;i<=m;i++){
88         printf("%lld/%lld\n",ask[i].a,ask[i].b);
89     }
90 return 0;
91 }
View Code

 

posted @ 2018-09-03 21:04  蒟蒻LQL  阅读(164)  评论(0编辑  收藏  举报