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就好了。
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]);
}
时间: 2024-09-29 22:54:10