您的位置:首页 > 其它

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

2016-05-07 22:44 197 查看

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]C2r−l+1=∑ni=1T[i]2−∑ni=nT[i](r−l+1)(r−l)=∑ni=1T[i]2−(r−l+1)(r−l+1)(r−l)ans={{\sum_{i=1}^n{C_{T[i]}^2}}\over{C_{r-l+1}^2}}={{\sum_{i=1}^n{T[i]^2}-\sum_{i=n}^nT[i]}\over{(r-l+1)(r-l)}}={{\sum_{i=1}^n{T[i]^2}-(r-l+1)}\over{(r-l+1)(r-l)}}

每次暴力维护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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: