zoukankan      html  css  js  c++  java
  • BZOJ-2038 小Z的袜子(hose) 莫队算法

    2038: [2009国家集训队]小Z的袜子(hose)
    Time Limit: 20 Sec Memory Limit: 259 MB
    Submit: 5573 Solved: 2568
    [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。

    HINT

    Source
    版权所有者:莫涛

    算法的创造者的自己的题目….
    关于莫队算法,处理区间的问题,离线操作…
    莫队算法的本质是个暴力….

    运算过程:
    莫队算法仅仅调整我们处理查询的顺序。我们得到了M个查询,我们将把查询以一个特定的顺序进行重新排序,然后处理它们。显然,这是一个离线算法。每个查询都有L和R,我们称呼其为“起
    点”和“终点”。让我们将给定的输入数组分为块。每一块的大小为 。每个“起点”落入其中的一块。每个“终点”也落入其中的一块。
    如果某查询的“起点”落在第p块中,则该查询属于第p块。该算法将处理第1块中的查询,然后处理
    第2块中的查询,等等,最后直到第块。我们已经有一个顺序、查询按照所在的块升序排列。可以有很多的查询属于同一块。
    从现在开始,我会忽略(其它,译者注,所有括号内斜体同)所有的块,只关注我们如何询问和回答第1块。我们将对所有块做同样的事。(第1块中的)所有查询的“起点”属于第1块,但“终点”可以在包括第1块在内的任何块中。现在让我们按照R值升序的顺序重新排列这些查询。我们也在所有的块中做这个操作。(指每个块块内按R升序排列。)
    最终的排序是怎样的? 所有的询问首先按照所在块的编号升序排列(所在块的编号是指询问的“起点”属于的块)。如果编号相同,则按R值升序排列。
    例如考虑如下的询问,假设我们会有3个大小为3的块(0-2,3-5,6-8): {0, 3} {1, 7} {2, 8} {7, 8} {4,
    8} {4, 4} {1, 2} 让我们先根据所在块的编号重新排列它们 {0, 3} {1, 7} {2, 8} {1, 2}
    (|){4, 8} {4, 4}(|) {7, 8} 现在我们按照R的值重新排列 {1, 2} {0, 3} {1, 7} {2,
    8}(|) {4, 4} {4, 8}(|) {7, 8}
    现在我们使用与上一节所述相同的代码来解决这个问题。上述算法是正确,因为我们没有做任何改变,只是重新排列了查询的顺序。
    不过强制要求在线,即不可莫队…

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    struct data1{int l,r,t;}ask[50010];
    struct data2{long long fm,fz;}ans[50010];
    int n,m,s;
    long long num[50010];
    int loc[50010];
    int color[50010];
    long long tmp;int l,r;
    
    long long gcd(long long a,long long b){if (b==0) return a;else return gcd(b,a%b);}
    
    void updata(int pos,int data)
    {
        tmp-=(long long)(num[color[pos]]*num[color[pos]]);
        num[color[pos]]+=data;
        tmp+=(long long)(num[color[pos]]*num[color[pos]]);
    }
    
    void work()
    {
        l=1;r=0;
        tmp=0;
        for (int i=1;i<=m;i++)
        {
            if (ask[i].l==ask[i].r)
            {
                ans[ask[i].t].fz=0;
                ans[ask[i].t].fm=1;
                continue;
            }
            while (r<ask[i].r) {r++;updata(r,1);}
            while (r>ask[i].r) {updata(r,-1);r--;}
            while (l<ask[i].l) {updata(l,-1);l++;}
            while (l>ask[i].l) {l--;updata(l,1);}
            ans[ask[i].t].fz=tmp-(r-l+1);
            ans[ask[i].t].fm=(long long)(r-l+1)*(r-l);
            long long d=gcd(ans[ask[i].t].fz,ans[ask[i].t].fm);
            ans[ask[i].t].fz=ans[ask[i].t].fz/d;
            ans[ask[i].t].fm=ans[ask[i].t].fm/d;
        }
    }
    
    bool cmp(data1 x,data1 y){if (loc[x.l]==loc[y.l]) return x.r<y.r; return loc[x.l]<loc[y.l];}
    
    int main()
    {
        n=read(),m=read();
        s=(int)sqrt(n);
        for (int i=1; i<=n; i++)
            {
                color[i]=read();
                loc[i]=(i-1)/s+1;
            }
        for (int i=1; i<=m; i++)
            ask[i].l=read(),ask[i].r=read(),ask[i].t=i;
        sort(ask+1,ask+m+1,cmp);
        work();
        for (int i=1; i<=m; i++)
            printf("%lld/%lld
    ",ans[i].fz,ans[i].fm);
        return 0;
    }
  • 相关阅读:
    c#项目架构搭建经验
    c++ template怎么使用及注意事项
    c++怎么将一个类,拆分出接口类,和实现类
    c++l类
    错过C++
    Fixed 鸟粪一样的TreeView下的NodeMouseDoubleClick Bug
    Oracle 12C 新特性之表分区带 异步全局索引异步维护(一次add、truncate、drop、spilt、merge多个分区)
    Oracle 12C 新特性之在线重命名、迁移活跃的数据文件
    Oracle 12C 新特性之级联truncate
    Oracle 12C 新特性之扩展数据类型(extended data type)
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346188.html
Copyright © 2011-2022 走看看