P1494 [国家集训队] 小 Z 的袜子

P1494 [国家集训队] 小 Z 的袜子

题目描述

作为一个生活散漫的人,小 Z 每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小 Z 再也无法忍受这恼人的找袜子过程,于是他决定听天由命……

具体来说,小 Z 把这 N 只袜子从 1N 编号,然后从编号 LR 的袜子中随机选出两只来穿。尽管小 Z 并不在意两只袜子是不是完整的一双,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

你的任务便是告诉小 Z,他有多大的概率抽到两只颜色相同的袜子。当然,小 Z 希望这个概率尽量高,所以他可能会询问多个 (L,R) 以方便自己选择。

然而数据中有 L=R 的情况,请特判这种情况,输出0/1

提示

100% 的数据中,N,M500001LRNCiN

Solution :

十分简单的莫队,非常适合入门。
我们发现分母是很容易确定的,所以我们统计分子就好了。考虑用桶维护区间内的颜色出现次数 baccol,我们新加一个节点 x ,假设其颜色为 baccol colx 那么区间内的点对 x 产生的贡献就是 baccolx

那么这个贡献显然是可以 O(1) 转移的,我们直接上莫队。

至于莫队算法嘛:

我似乎不能用比较精炼的语言概括其思想,但是它能应用的特征十分明显:询问离线,无修改操作,插入或删除一个点时,重新统计贡献的复杂度不高。

算法流程:

我们将所有询问排序,用两个指针 l,r 维护当前区间,在状态转移时移动指针。

Code:

#include<bits/stdc++.h>
#define int long long
const int N=5e4+5;
using namespace std;
int a[N],bac[N],blo[N],ans[N],len[N];
struct task{
int l,r,L,R,id;
bool operator<(const task &t)const{
return l==t.l ? (l&1 ? R<t.R : t.R<R) :l < t.l;
}
}q[N];
int n,m,S,sum;
inline void add(int x){sum+=bac[a[x]]++;}
inline void del(int x){sum-=--bac[a[x]];}
int gcd(int x,int y){return y ? gcd(y,x%y) : x;}
void work()
{
cin>>n>>m;
S=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
blo[i]=(i-1)/S+1;
}
for(int i=1,l,r;i<=m;i++)
{
scanf("%lld%lld",&l,&r);
q[i]={blo[l],blo[r],l,r,i};
len[i]=r-l+1;
}
sort(q+1,q+1+m);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
while(r<q[i].R)add(++r);
while(l<q[i].L)del(l++);
while(q[i].L<l)add(--l);
while(q[i].R<r)del(r--);
ans[q[i].id]=sum<<1;
}
for(int i=1;i<=m;i++)
{
len[i]*=len[i]-1;
if(len[i])
{
int d=gcd(ans[i],len[i]);
printf("%lld/%lld\n",ans[i]/d,len[i]/d);
}
else
{
printf("0/1\n");
}
}
}
#undef int
int main()
{
//freopen("P1494_1.in","r",stdin);freopen("P1494.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示