码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-12-21 20:43:24      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:return   turn   tar   sum   ref   typedef   block   概率   namespace   

【传送门: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)

标签:return   turn   tar   sum   ref   typedef   block   概率   namespace   

原文地址:http://www.cnblogs.com/Never-mind/p/8073379.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!