BZOJ 2038小Z的袜子 分块

来源:互联网 发布:淘宝开店装修模板 编辑:程序博客网 时间:2024/04/18 13:54

题意:给定一列数字,然后给出一堆询问 询问在闭区间[l,r]里面随便抽取两个袜子同色的概率是多少

解法:先要求出在闭区间[l,r]里面有多少的组合方式使得两个袜子同色 然后我们就可以直接和在区间长度中抽取两个数的方案数约分一下就可以了 

当然是用分块比较容易实现修改 每次添加一个数增加的方案数就是当前这个颜色的个数-1 每次删去一个数就是方案数减去当前要删的颜色的数量-1 然后就可以在O(1)里面实现转移了

当然用块状数组也是可以的 但是代码量就比较多了 

#include<cstdio>#include<string.h>#include<iostream>#include<algorithm>#define sqr 224#define maxn 55555#define LL long longusing namespace std;int id[maxn],ll[maxn],rr[maxn],a[maxn];LL cnt[maxn],ans[maxn],len[maxn];LL gcd(LL a,LL b){    return (b>0)?gcd(b,a%b):a;}int n,m;int cmp(int x,int y){    if(ll[x]/sqr==ll[y]/sqr){        return rr[x]<rr[y];    }return ll[x]<ll[y];}int main(){        scanf("%d%d",&n,&m);        for(int i=0;i<n;++i)scanf("%d",&a[i]);        for(int i=0;i<m;++i){            scanf("%d%d",&ll[i],&rr[i]);--ll[i],--rr[i];            id[i]=i;        }        memset(cnt,0,sizeof cnt);        memset(len,0,sizeof len);        sort(id,id+m,cmp);        int nowl=0,nowr=-1;LL tot=0;        for(int i=0;i<m;++i){            int l=ll[id[i]],r=rr[id[i]];            while(nowr<r){tot+=cnt[a[++nowr]]++;}            while(nowl>l){tot+=cnt[a[--nowl]]++;}            while(nowr>r){tot-=--cnt[a[nowr--]];}            while(nowl<l){tot-=--cnt[a[nowl++]];}            if(tot==(LL)0)ans[id[i]]=(LL)0;            else{                 len[id[i]]=(LL)(r-l+1)*(LL)(r-l)/(LL)2;                 ans[id[i]]=tot;            }        }                for(int i=0;i<m;++i)            if(ans[i]==(LL)0){                printf("0/1\n");            }else{                LL pr=gcd(ans[i],len[i]);                printf("%lld/%lld\n",ans[i]/pr,len[i]/pr);            }    return 0;}


0 0