zoukankan      html  css  js  c++  java
  • BZOJ 2038 [2009国家集训队]小Z的袜子(hose)

     

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

    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。

    Source

    版权所有者:莫涛


      这是一道极为经典的题目。注意到一点,如果我们有计算完[L, R]时的“中间变量”(在本题为每个数出现的次数),那么[L - 1, R]、[L + 1, R]、[L, R - 1]、[L, R + 1]都能够在“中间变量”的“基本操作时间复杂度”(O(1)orO(log n)……)得出。

      例如在此题中,我们如果列出算式,可以轻易发现[L,R]对应的答案通过区间内各颜色数目的平方和快速计算,如果辅助存储区间内各颜色数目,那么O(1)的比邻状态转移就能够实现。

      以此便可介入此题。发现对于一个询问,可以从上一个询问开始通过移动区间得到现有答案。但是,这样很明显不优。状态间的转移即是左端点与右端点的位移,复杂度就是abs(L1 - L2) + abs(R1 - R2)。如果出题人足够邪恶,以至于一次转移是O(n)的,总的算下来O(nq)绝对无法接受。(但我做了实验并没有TLE)。

      当然,有人会说,这道题并没有强制在线,我们可以按照恰当的顺序去解决每个询问。例如,按照左端点从小到大排序,如果左端点相同再右端点从小到大排序。这样确实似乎可以,但出题人也可以乱卡,让右端点乱跳,一次转移同样可以做到O(n)。

      于是,就有人强推曼哈顿最小生成树(可以让顺序完美),但代码复杂度太高,同样也是O(nlogn)的复杂度。我们信息学竞赛不是“完美主义”,很有可能因小失大。

      于是“莫队”(因为比赛常常当队长)说,可以把左端点的排序“模糊处理”,允许在一定区间内的左端点其右端点单调递增。一定区间?这大概就是分块了。我们并不需要去专门维护这个块,只是在排序时用到。假设块长O(k),而一个块右端点最多跳O(n),有O(n/k)个块,故右端点最多跳O(n^2/k)次。左端点每次最多跳O(k)次,故左端点最多跳O(nk)次。

      我们发现,左右端点乱跳次数的乘积是相对一定的,为O(n^3),所以若k=sqrt(n),结果最优,复杂度是O(n*sqrt(n))的。

      但是,话说回来,这类题目为什么不能使用线段树一类的数据结构?理由很简单,颜色太多了。但据说有很强的方法,反正我不会。

      最后说一句,这道题要A特别简单。注:“莫队算法”=分块离线暴力

    Type 直接按照顺序做 无脑排序 分块排序
    Time 12228 ms 5680 ms

    568 ms

      当然,可以只sort一次,能开int就开int。904 ms-〉812 ms-〉764 ms-〉568 ms

     1 /************************************************************** 
     2     Problem: 2038 
     3     User: Doggu 
     4     Language: C++ 
     5     Result: Accepted 
     6     Time:568 ms 
     7     Memory:2592 kb 
     8 ****************************************************************/
     9   
    10 #include <cstdio> 
    11 #include <algorithm> 
    12 #include <cmath> 
    13 using namespace std; 
    14 template<class T>inline void readin(T &res) { 
    15     static char ch;T flag=1; 
    16     while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1; 
    17     res=ch-48; 
    18     while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48; 
    19     res*=flag; 
    20 } 
    21 const int N = 50010; 
    22 const int Q = 50010; 
    23 int n, q, K, aa[N], num[N]; 
    24 struct data{ 
    25     int L, R, ord; 
    26     bool operator< (const data &rhs) const {return L/K==rhs.L/K?R<rhs.R:L<rhs.L;} 
    27 }que[Q]; 
    28 long long x[N], y[N];inline long long gcd(long long a,long long b) {if(b==0) return a;return gcd(b,a%b);} 
    29 int main() { 
    30     readin(n);readin(q);K=floor(sqrt(n)); 
    31     for( int i = 1; i <= n; i++ ) readin(aa[i]); 
    32     for( int i = 1; i <= q; i++ ) readin(que[i].L),readin(que[i].R),que[i].ord=i; 
    33     sort(que+1,que+q+1); 
    34     int L = 1, R = 0, tot = 0; 
    35     long long xs, ys, temp; 
    36     for( int i = 1; i <= q; i++ ) { 
    37         while(R<que[i].R) { 
    38             R++; 
    39             tot+=2*num[aa[R]]+1; 
    40             num[aa[R]]++; 
    41         } 
    42         while(que[i].R<R) { 
    43             num[aa[R]]--; 
    44             tot-=2*num[aa[R]]+1; 
    45             R--; 
    46         } 
    47         while(que[i].L<L) { 
    48             L--; 
    49             tot+=2*num[aa[L]]+1; 
    50             num[aa[L]]++; 
    51         } 
    52         while(L<que[i].L) { 
    53             num[aa[L]]--; 
    54             tot-=2*num[aa[L]]+1; 
    55             L++; 
    56         } 
    57         xs=tot-(R-L+1);ys=(long long)(R-L+1)*(R-L);temp=gcd(xs,ys); 
    58         x[que[i].ord]=xs/temp;y[que[i].ord]=ys/temp; 
    59     } 
    60     //sort(que+1,que+q+1,cmp2); 
    61     for( int i = 1;i <= q; i++ ) printf("%lld/%lld
    ",x[i],y[i]); 
    62     return 0; 
    63 }
    莫队

      

  • 相关阅读:
    使用C++调用并部署pytorch模型
    相位展开(phase unwrapping)算法研究与实践
    【计算机视觉】图像配准(Image Registration)
    读书笔记 - 《数字图像处理》(更新中...)
    ssh框架复习
    SVN 版本控制
    Spring的jdbcTemplate 与原始jdbc 整合c3p0的DBUtils 及Hibernate 对比 Spring配置文件生成约束的菜单方法
    JDK 动态代理 讨债实例
    Spring 框架配置web.xml 整合web struts
    Spring整合JUnit spring静态对象属性的注入
  • 原文地址:https://www.cnblogs.com/Doggu/p/bzoj2038.html
Copyright © 2011-2022 走看看