【2010集训队出题】小Z的袜子

来源:互联网 发布:三位一体mac 编辑:程序博客网 时间:2024/05/17 01:42

Description

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

Solution

一道莫队算法的裸题。莫队算法学习小记
设一个T[i]表示上一个询问的i出现的次数,每次遇到一个a就T[a]++;

ans=ni=1C2T[i]C2rl+1=ni=1T[i]2ni=nT[i](rl+1)(rl)=ni=1T[i]2(rl+1)(rl+1)(rl)

每次暴力维护ans就好了。

Solution

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=50007;typedef long long ll;ll i,j,k,l,t,n,m,r,ans1,kuai;ll ans[maxn][2],T[maxn];ll c[maxn];struct node{    ll a,b,c,d,e;}a[maxn];bool cmp(node x,node y){    return x.d<y.d||x.d==y.d&&x.e<y.e;}void update(ll l,ll r,ll z){    int j;    fo(j,l,r)ans1-=T[c[j]]*T[c[j]],T[c[j]]+=z,ans1+=T[c[j]]*T[c[j]];}ll gcd(ll x,ll y){return (y)?gcd(y,x%y):x;}int main(){    scanf("%lld%lld",&n,&m);    kuai=sqrt(n);    fo(i,1,n)scanf("%lld",&c[i]);    fo(i,1,m){        scanf("%lld%lld",&a[i].a,&a[i].b);        a[i].d=(a[i].a-1)/kuai+1;        a[i].e=(a[i].b-1)/kuai+1;        a[i].c=i;    }    sort(a+1,a+1+m,cmp);    l=1;r=0;    fo(i,1,m){        k=a[i].a;t=a[i].b;        if(k>l)update(l,k-1,-1);        else if(k<l)update(k,l-1,1);        if(t>r)update(r+1,t,1);        else if(r>t)update(t+1,r,-1);        l=k;r=t;        ans[a[i].c][0]=ans1-(t-k+1);        ans[a[i].c][1]=(t-k+1)*(t-k);        if(ans[a[i].c][0]==0){            ans[a[i].c][0]=0;ans[a[i].c][1]=1;        }        else{            ll u=gcd(ans[a[i].c][0],ans[a[i].c][1]);            ans[a[i].c][0]/=u;            ans[a[i].c][1]/=u;        }    }    fo(i,1,m)printf("%lld/%lld\n",ans[i][0],ans[i][1]);}
1 0