[BZOJ2038/Luogu1494][2009国家集训队]小Z的袜子(莫队算法,离线)

发布于 2018-01-28  55 次阅读


本文章由SYCstudio或本站其它作者所有,严禁转载,转载必究

本文链接地址:[BZOJ2038/Luogu1494][2009国家集训队]小Z的袜子(莫队算法,离线)

Description

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

Http

BZOJ
Luogu

Tag

莫队算法,离线

解决思路

早就想学莫队算法了,今天总算认真学了一次。
先来看看这一道题吧。
考虑区间[l,r],记\(Sum[i]\)表示这个范围内颜色\(i\)的个数。那么这个区间内的答案就是\(\frac{\sum Sum[i]*(Sum[i]-1)}{len*(len-1)}\),其中\(len\)是区间长。化简一下得到\(\frac{\sum Sum[i]^2-\sum Sum[i]}{len*(len-1)}=\frac{\sum Sum[i]^2-len}{len*(len-1)}\)。那么关键就是求\(Sum[i]^2\)。
考虑按长度\(\sqrt{n}\)分块,若左端点在同一个块内,按右端点排序,否则按左端点排序。然后从前往后移动指针即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

#define ll long long
#define mem(Arr,x) memset(Arr,x,sizeof(Arr))
#define sqr(x) (((ll)x)*((ll)x))

const int maxN=50010;
const int inf=2147483647;

class Data
{
public:
    int l,r,id;
    ll A,B;
};

int n,m,size;
ll Ans=0;
int Belong[maxN],Color[maxN],Sum[maxN];
Data Q[maxN];

bool cmp1(Data A,Data B);
bool cmp2(Data A,Data B);
void Move(ll pos,ll opt);
ll gcd(ll a,ll b);

int main()
{
    scanf("%d%d",&n,&m);size=sqrt(n);//分块大小
    for (int i=1;i<=n;i++) scanf("%d",&Color[i]),Belong[i]=(i-1)/size+1;//求出每一个点所属的块
    for (int i=1;i<=m;i++) scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].id=i;
    sort(&Q[1],&Q[m+1],cmp1);
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        //移动指针
        while (l<Q[i].l) Move(l,-1),l++;
        while (l>Q[i].l) Move(l-1,1),l--;
        while (r<Q[i].r) Move(r+1,1),r++;
        while (r>Q[i].r) Move(r,-1),r--;
        Q[i].A=(ll)Ans-(ll)(Q[i].r-Q[i].l+1);
        Q[i].B=(ll)(Q[i].r-Q[i].l+1)*(ll)(Q[i].r-Q[i].l);
    }
    sort(&Q[1],&Q[m+1],cmp2);
    for (int i=1;i<=m;i++)
        if (Q[i].A==0) printf("0/1\n");
        else
        {
            ll g=gcd(Q[i].A,Q[i].B);
            printf("%lld/%lld\n",Q[i].A/g,Q[i].B/g);
        }
    return 0;
}

bool cmp1(Data A,Data B)
{
    if (Belong[A.l]==Belong[B.l]) return A.r<B.r;
    else return A.l<B.l;
}

bool cmp2(Data A,Data B)
{
    return A.id<B.id;
}

void Move(ll pos,ll opt)
{
    Ans-=sqr(Sum[Color[pos]]);
    Sum[Color[pos]]+=opt;
    Ans+=sqr(Sum[Color[pos]]);
}

ll gcd(ll a,ll b)
{
    ll tmp;
    while (b) tmp=a,a=b,b=tmp%b;
    return a;
}

本文章由SYCstudio或本站其它作者所有,严禁转载,转载必究

本文链接地址:[BZOJ2038/Luogu1494][2009国家集训队]小Z的袜子(莫队算法,离线)


HNCJ OIer 一枚