zoukankan      html  css  js  c++  java
  • [BZOJ2038] [2009国家集训队]小Z的袜子(hose) 莫队算法练习

    2038: [2009国家集训队]小Z的袜子(hose)

    Time Limit: 20 Sec  Memory Limit: 259 MB
    Submit: 10299  Solved: 4685
    [Submit][Status][Discuss]

    Description

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……
    具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
    你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

    Input

    输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。

    Output

    包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。(详见样例)

    Sample Input

    6 4
    1 2 3 3 3 2
    2 6
    1 3
    3 5
    1 6

    Sample Output

    2/5
    0/1
    1/1
    4/15
    【样例解释】
    询问1:共C(5,2)=10种可能,其中抽出两个2有1种可能,抽出两个3有3种可能,概率为(1+3)/10=4/10=2/5。
    询问2:共C(3,2)=3种可能,无法抽到颜色相同的袜子,概率为0/3=0/1。
    询问3:共C(3,2)=3种可能,均为抽出两个3,概率为3/3=1/1。
    注:上述C(a, b)表示组合数,组合数C(a, b)等价于在a个不同的物品中选取b个的选取方案数。
    【数据规模和约定】
    30%的数据中 N,M ≤ 5000;
    60%的数据中 N,M ≤ 25000;
    100%的数据中 N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。
     
     
    表示蒟蒻并没有看出来是莫队(不熟练)。
    先简述一下莫队算法,
    莫队算法用于离线处理区间问题。当然它只能处理能在O(1)的时间从【l,r】转移到【l-1,r】【l+1,r】【l,r-1】【l,r+1】的问题。
    具体思路如下:
    设区间长度为n,
    首先对查询进行分块,按照左端点的大小分成sqrt(n)块并按所属块排序,在每块内再按右端点的大小排序,之后从区间(0,0)一步一步移到排序好的下一个询问。然后将询问回复原序输出答案。
    那么问题来了,时间复杂度是多少?
    下面给出时间复杂度的证明:
    首先,我们发现对于一个询问【l,r】我们能将其抽象为平面上的一个点(l,r)。
    所以从一个询问走到下一个询问的时间是曼哈顿距离。
    现在,我们已经分好了sqrt(n)块。
    先考虑r,对于两个点,如果在同一个块,对于这两个点所处的块r单调,所以每一块r最多为O(n),由于有sqrt(n)个块,所以复杂度为O(n √n)
    如果两个点在不同的块,r最多变化n,由于有√n块,所以复杂度为O(n√n)
    再考虑l,如果两点在同一块,l变化不超过√n,如果两点不在同一块l变化同样不超过√n,由于有m个询问,所以时间复杂度为O(n√n) (n与m同级)
    所以总复杂度为O(n√n)
     
    下面是此题代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define LL long long
     8 using namespace std;
     9 LL n,m;
    10 LL c[50001];
    11 struct ask
    12 {
    13     LL l,r,id,a,b;
    14 }a[50001];
    15 LL belong[50001];
    16 LL size=0;
    17 bool cmp(ask t1,ask t2)
    18 {
    19     if(belong[t1.l]==belong[t2.l]) return t1.r<t2.r;
    20     return t1.l<t2.l;
    21 }
    22 bool cmp1(ask t1,ask t2){return t1.id<t2.id;}
    23 LL ans=0;
    24 LL s[50001];
    25 void update(int now,int add)
    26 {
    27     if(s[c[now]]>0)
    28         ans-=s[c[now]]*(s[c[now]]-1);
    29     s[c[now]]+=add;
    30     if(s[c[now]]>0)
    31         ans+=s[c[now]]*(s[c[now]]-1);
    32 }
    33 LL gcd(LL x,LL y){return y==0?x:gcd(y,x%y);}
    34 void solve()
    35 {
    36     LL l=1,r=0;
    37     for(int i=1;i<=m;i++)
    38     {
    39         for(;r<a[i].r;r++) update(r+1,1);
    40         for(;r>a[i].r;r--) update(r,-1);
    41         for(;l<a[i].l;l++) update(l,-1);
    42         for(;l>a[i].l;l--) update(l-1,1);
    43         if(r==l){a[i].a=0,a[i].b=1;continue;}
    44         a[i].a=ans,a[i].b=(r-l+1)*(r-l); 
    45         LL g=gcd(a[i].a,a[i].b);
    46         a[i].a/=g;
    47         a[i].b/=g;
    48     }
    49 }
    50 int main()
    51 {
    52     scanf("%lld%lld",&n,&m);
    53     size=sqrt(n);
    54     for(int i=1;i<=n;i++) belong[i]=(i-1)/size+1;
    55     for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
    56     for(int i=1;i<=m;i++)
    57     {
    58         scanf("%lld%lld",&a[i].l,&a[i].r);
    59         a[i].id=i;
    60     }
    61     sort(a+1,a+m+1,cmp);
    62     solve();
    63     sort(a+1,a+m+1,cmp1);
    64     for(int i=1;i<=m;i++) printf("%lld/%lld
    ",a[i].a,a[i].b);
    65 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    oracle查看所有角色
    jQuery 异步提交表单实例解析
    oracle查看用户系统权限
    js中日期操作大全
    oracle 查询用户下所有表
    JS语法字典
    JS定时器例子讲解
    开源软件
    rpm的使用
    lvs+keepalived和haproxy+heartbeat区别
  • 原文地址:https://www.cnblogs.com/wls001/p/7192842.html
Copyright © 2011-2022 走看看