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;
}
原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346188.html