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

Posted Star_Feel

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2038: [2009国家集训队]小Z的袜子(hose)相关的知识,希望对你有一定的参考价值。

【传送门:BZOJ2038


简要题意:

  给出n只袜子,每只袜子都有颜色

  有多个询问,每次询问一个区间L,R,求出在这个区间内选出两只相同颜色袜子的概率,以最简分数形式输出(不用化成整数,如果概率为0,则输出0/1)


题解:

  接触莫队第一题

  我们先假设当前要询问的区间内第一种颜色的袜子有a只,第二种有b只......最后一种颜色的袜子有x只

  那么我们输出的答案应该是:$ans=\\frac{\\frac{a(a-1)}{2}+\\frac{b(b-1)}{2}+...+\\frac{x(x-1)}{2}}{\\frac{(R-L+1)(R-L)}{2}}$

  我们来化简一下,得到:

  $$ans=\\frac{a(a-1)+b(b-1)+...+x(x-1)}{(R-L+1)(R-L)}$$

  $$ans=\\frac{a^2-a+b^2-b+...+x^2-x}{(R-L+1)(R-L)}$$

  $$ans=\\frac{a^2+b^2+...+x^2-(a+b+...+x)}{(R-L+1)(R-L)}$$

  $$ans=\\frac{a^2+b^2+...+x^2-(R-L+1)}{(R-L+1)(R-L)}$$

  然后我们对它来进行莫队求解

  最后来膜一膜大米饼


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b){if(a==0) return b;return gcd(b%a,a);}
struct node
{
    LL x,y;
    int id,l,r;
}a[51000];
int bk[51000];
bool cmp1(node n1,node n2)
{
    return bk[n1.l]==bk[n2.l]?n1.r<n2.r:bk[n1.l]<bk[n2.l];
}
bool cmp2(node n1,node n2)
{
    return n1.id<n2.id;
}
int col[51000];
LL sum[51000];
LL x;
void update(int p,int c)
{
    x-=sum[col[p]]*sum[col[p]];
    sum[col[p]]+=c;
    x+=sum[col[p]]*sum[col[p]];
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int block=int(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&col[i]);
        bk[i]=(i-1)/block+1;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].id=i;
    }
    sort(a+1,a+m+1,cmp1);
    memset(sum,0,sizeof(sum));
    int l=1,r=0;x=0;
    for(int i=1;i<=m;i++)
    {
        while(l<a[i].l){update(l,-1);l++;}
        while(l>a[i].l){update(l-1,1);l--;}
        while(r<a[i].r){update(r+1,1);r++;}
        while(r>a[i].r){update(r,-1);r--;}
        if(a[i].l==a[i].r){a[i].x=0;a[i].y=1;continue;}
        a[i].x=x-(r-l+1);a[i].y=LL(r-l+1)*LL(r-l);
        LL gd=gcd(a[i].x,a[i].y);
        a[i].x/=gd;a[i].y/=gd;
    }
    sort(a+1,a+m+1,cmp2);
    for(int i=1;i<=m;i++) printf("%lld/%lld\\n",a[i].x,a[i].y);
    return 0;
}

 

以上是关于BZOJ2038: [2009国家集训队]小Z的袜子(hose)的主要内容,如果未能解决你的问题,请参考以下文章

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

BZOJ 2038 2009国家集训队 小z的袜子(house)

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

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

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

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