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

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

时间:2016-02-22 23:32:30      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:

这是个很奇怪的东西,不过有n*sqrt(n)的时间复杂度保证, 所以直接乱搞

一个区间[l,r]内抽到同种颜色袜子的概率(设num[i]表示该区间中颜色为i的袜子数量)

                     sum( num[i])*(num[i]-1) ) / (r-l+1)*(r-l), (1<=i<=n)

分母很容易求出来,我们单独考虑分子,上式化简为

                     (sum(num[i]*num[i]) - sum(num[i])) / (r-l+1)*(r-l)

而sum([i])就是这个区间的长度, 所以我们只要先统计平方和,最后减去区间长度即可

对于已知答案的区间[l,r],可以O(1)时间算出[l-1,r],[l,r+1],[l+1,r],[l,r-1]的答案(由于区间只改动了1,只有一种颜色数量改变,只要减去原来数量的平方,加上新的数量的平方)

离线处理询问:先将n分成sqrt(n)块,然后先按每个询问的l所在块的编号从小到大排序,相同块按r排序(为什么这样,可能是因为相邻区间的l和r间就相差比较少,可以发挥上面性质的优点)

然后再YY一下得到如下代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) {
    return b?gcd(b,a%b):a;
}
int n,m,sum,sqn,pc[50007],c[50007],num[50007];
ll ans;
struct query{
    int l,r,id;
    ll a,b;
    inline void read(int i){scanf("%d%d",&l,&r);id=i;}
    bool operator < (const query& b)const{
        return pc[l]<pc[b.l]||(pc[l]==pc[b.l]&&r<b.r)||(pc[l]==pc[b.l]&&r==b.r&&l<b.l);
    }
}Q[50007];
bool cmp(const query& a,const query& b){return a.id<b.id;}
int main() {
    scanf("%d%d",&n,&m);sqn=sqrt(n);
    for(int i=1,j=0;i<=n;i++){
        scanf("%d",&c[i]);
        if(i%sqn==1) j++; 
        pc[i]=j;
    }
    for(int i=1;i<=m;i++) Q[i].read(i);
    sort(Q+1,Q+m+1);
    int l=1,r=0;
    for(int i=1;i<=m;i++){
        int p=Q[i].l,q=Q[i].r;
        while(r<q)r++,num[c[r]]++,ans+=num[c[r]]*num[c[r]]-(num[c[r]]-1)*(num[c[r]]-1);
        while(l<p)ans+=(num[c[l]]-1)*(num[c[l]]-1)-num[c[l]]*num[c[l]],num[c[l]]--,l++;
        while(r>q)ans+=(num[c[r]]-1)*(num[c[r]]-1)-num[c[r]]*num[c[r]],num[c[r]]--,r--;
        while(l>p)l--,num[c[l]]++,ans+=num[c[l]]*num[c[l]]-(num[c[l]]-1)*(num[c[l]]-1);
        Q[i].a=ans-(q-p+1);Q[i].b=(ll)(q-p+1)*(q-p);
    }
    sort(Q+1,Q+m+1,cmp);
    for(int i=1;i<=m;i++) {
        ll Gcd=gcd(Q[i].a,Q[i].b);
        if(!Q[i].a) printf("0/1\n");
        else printf("%lld/%lld\n",Q[i].a/Gcd,Q[i].b/Gcd);
    }
    return 0;
}

 

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

标签:

原文地址:http://www.cnblogs.com/usingnamespace/p/5208372.html

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