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


    Description

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

    Solution

    把询问按照左端点排序,块内按照右端点排序;

    (l,r)的答案转移到(l+1,r)/(l-1,r)/(l,r+1)/(l,r-1)只需要O(1)的时间,所以总的时间复杂度是O(n^1.5)【黄学长blog有时间复杂度的分析 hzwer

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 50005
    typedef long long LL;
    using namespace std;
    int n,m,unit,col[MAXN],num[MAXN];
    LL ans=0;
    struct Node{
        int l,r,id;
        LL a,b;
    }q[MAXN];
    int Read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    bool cmp(Node A,Node B)
    {
        if(A.l/unit!=B.l/unit)
        return A.l/unit<B.l/unit;
        return A.r<B.r;
    }
    bool cmp_id(Node A,Node B)
    {
        return A.id<B.id;
    }
    LL gcd(LL a,LL b)
    {
        if(!b)return a;
        return gcd(b,a%b);
    }
    void update(int x,int add)
    {
        ans-=num[col[x]]*(num[col[x]]-1);
        num[col[x]]+=add;
        ans+=num[col[x]]*(num[col[x]]-1);
    }
    void work()
    {
        int L=1,R=0;
        for(int i=0;i<m;i++)
        {
            while(q[i].l<L)update(L-1,1),L--;
            while(q[i].l>L)update(L,-1),L++;
            while(q[i].r<R)update(R,-1),R--;
            while(q[i].r>R)update(R+1,1),R++;
            if(q[i].l==q[i].r){q[i].a=0,q[i].b=1;continue;}
            q[i].a=ans;
            q[i].b=(LL)(R-L+1)*(R-L);
            LL k=gcd(q[i].a,q[i].b);
            q[i].a/=k,q[i].b/=k;
        }
    }
    int main()
    {
        n=Read();m=Read();
        unit=sqrt(n);
        for(int i=0;i<n;i++)
        col[i]=Read();
        for(int i=0;i<m;i++)
        {
            q[i].l=Read()-1;
            q[i].r=Read()-1;
            q[i].id=i;
        }
        sort(q,q+m,cmp);
        work();
        sort(q,q+m,cmp_id);
        for(int i=0;i<m;i++)
        {
            printf("%lld/%lld
    ",q[i].a,q[i].b);
        }
        return 0;
    } 
  • 相关阅读:
    今天学会了如何察看SSDT里面的东西、修改里面的地址
    今天。。。。忙了一天
    我承认,我怕,我很怕
    WinCE下的第二个窗口程序
    终于搭好了WinCE上MFC的SDK环境
    原来腾迅的QQ号竟然是个int变量
    操了,编译器,你就不能少给我下几个断么
    谁能教我网络编程阿
    反汇编。。。本来以为很难,原来却这么容易
    PE头里的东西更多。。。越看越恶心了,我都不想看了
  • 原文地址:https://www.cnblogs.com/Zars19/p/6681508.html
Copyright © 2020-2023  润新知