题目链接:https://www.luogu.org/problemnew/show/P1494

题目描述

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

具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

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

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

输入输出格式

输入格式:

输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。

输出格式:

包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。(详见样例)

输入输出样例

输入样例#1:

6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6
输出样例#1:

2/5
0/1
1/1
4/15

说明

30%的数据中 N,M ≤ 5000;

60%的数据中 N,M ≤ 25000;

100%的数据中 N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

题解:

直接上线段树的话,由于不满足区间可加性:

假设现在要计算区间 $[L,R]$ 里每一种颜色的袜子的数量,此时我们已经分别维护好了左右两边区间 $[L,mid]$ 和 $[mid+1,R]$ 中每一种颜色的袜子的数量,然后开始向上维护:

就会发现,依然要把每种颜色的袜子在左右区间的数量加起来才能完成对一个父节点的维护,我们并不能在 $O(1)$ 的时间内完成对线段树单一节点的维护。

但此时,若已知一个区间 $[ L , R ]$ 的情况,我们可以在 $O(1)$ 的时间内确定的有 $[ L , R+1 ]$ 和 $[ L , R-1 ]$ 和 $[ L-1 , R ]$ 和 $[ L+1 , R ]$ 的情况,

假设我们现在已知 $[ L , R ]$ 的情况,需要计算的是 $[ L' , R' ]$ 的情况,易知所需时间复杂度为 $O( | L - L' | + | R - R' | )$,

那么怎么样能够较快地回答 $M$ 次询问呢?

考虑将整个长度为 $N$ 的分成 $\frac{N}{S}$ 块,每一块长度为 $S$,所有的询问先按左端点所属分块的编号进行升序排序,对于分块编号相同的,则按右端点的大小升序排序,

那么,经过排序之后按照新的顺序遍历所有询问,每次回答当前的询问,都要以上一次询问为基础,分别考虑从上一次询问到当前询问的转移中左右两个端点的变动:

对于左端点:

  上一次询问和当前询问同属一个分块时,注意左端点不是有序的,那么最多从块的一端移到另一端 $O(S)$;

  即使跨块,考虑询问的左端点是随机生成的,当 $M$ 和 $N$ 同数量级时,一般来说每个分块下面都应当存在大约 $\frac{MS}{N}$ 个询问,那么前后两次询问的转移基本就是两个相邻块间的转移,因此移动距离也是 $O(S)$;

  总共有 $M$ 个询问,总的时间复杂度是 $O(MS)$。

对于右端点:

  上一次询问和当前询问同属一个分块时,同个分块内的右端点是有序的,那么易知遍历一个分块中所有询问,右端点最多就是从 $1$ 一直移动到 $N$,一整个分块内右端点移动 $O(N)$ 次;

  而遇到上一次询问和当前询问是跨块的情形,最差的情况不过就是右端点从 $N$ 回到 $1$,也是 $O(N)$ 次;

  共 $O(\frac{N}{S})$ 个分块,所有前后两次询问的变动属于分块内变动的,合起来使得右端点共移动 $O(\frac{N^2}{S})$ 次;

  最多 $O(\frac{N}{S})$ 次跨块变动,所有前后两次询问的变动为跨快变动的,合起来使得右端点共移动 $O(\frac{N^2}{S})$ 次;

  两者加起来,时间复杂度依然 $O(\frac{N^2}{S})$。

综上,莫队的时间复杂度是 $O(MS + \frac{N^2}{S})$,取 $S = \frac{N}{\sqrt M}$,可使得时间复杂度最小为 $O(N \sqrt M)$。

那么假设某个区间 $[L,R]$ 有 $X(X \ge 2)$ 只不同袜子,那么任取两只袜子的情况数是 $C_X^2$,

假设区间内的袜子有 $1 \sim K$ 共 $K$ 种颜色,假设第 $k$ 个颜色的袜子数为 $num[k]$,那么取到同种颜色的两只袜子的可能数是 $C_{num\left[ 1 \right]}^2 + C_{num\left[ 2 \right]}^2 + \cdots + C_{num\left[ K \right]}^2$ ,

根据组合数公式可知 $C_n^2 = \frac{{n\left( {n - 1} \right)}}{2}$ ,

所以取到两只同色袜子的概率为

由于 $X = R - L + 1$ ,我们实际要查询的就是 $Q\left( {L,R} \right) = \sum\limits_{k = 1}^K {num\left[ k \right]^2 }$ ,

那么,

若区间转移时增加一只颜色为 $c$ 的袜子:

$Q\left( {L,R + 1} \right) = Q\left( {L - 1,R} \right) = Q\left( {L,R} \right) - num\left[ c \right]^2 + \left( {num\left[ c \right] + 1} \right)^2 = Q\left( {L,R} \right) + 2 \times num\left[ c \right] + 1$

若区间转移时减少一只颜色为 $c$ 的袜子:

$Q\left( {L,R - 1} \right) = Q\left( {L{\rm{ + }}1,R} \right) = Q\left( {L,R} \right) - num\left[ c \right]^2 + \left( {num\left[ c \right] - 1} \right)^2 = Q\left( {L,R} \right) - 2 \times num\left[ c \right] + 1$

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn=+;
const int maxm=+; struct Query
{
int block; //表示左端点所在块
int id; //表示询问的原始顺序
int l,r;
Query(){}
Query(int _blk,int _id,int _l,int _r){block=_blk,id=_id,l=_l,r=_r;}
bool operator <(const Query &oth)const
{
return (block==oth.block)?(r<oth.r):(block<oth.block);
}
};
vector<Query> Q; int n,m;
int c[maxn],num[maxn];
ll up[maxn],down[maxn]; inline ll gcd(ll a,ll b){return b==?a:gcd(b,a%b);} int main()
{
while(cin>>n>>m)
{
int len=n/sqrt(m);
for(int i=;i<=n;i++) scanf("%d",&c[i]);
Q.clear();
for(int i=,l,r;i<=m;i++)
{
scanf("%d%d",&l,&r);
Q.push_back(Query(l/len,i,l,r));
}
sort(Q.begin(),Q.end()); memset(num,,sizeof(num));
int pl=,pr=;
ll ans=;
for(int i=;i<Q.size();i++)
{
const Query& q=Q[i];
if(q.l==q.r)
{
up[q.id]=;
down[q.id]=;
continue;
}
down[q.id]=(ll)(q.r-q.l+)*(q.r-q.l);
if(pr<q.r)
{
for(int j=pr+;j<=q.r;j++)
{
ans=ans+*num[c[j]]+;
num[c[j]]++;
}
}
if(pr>q.r)
{
for(int j=pr;j>q.r;j--)
{
ans=ans-*num[c[j]]+;
num[c[j]]--;
}
}
if(pl>q.l)
{
for(int j=pl-;j>=q.l;j--)
{
ans=ans+*num[c[j]]+;
num[c[j]]++;
}
}
if(pl<q.l)
{
for(int j=pl;j<q.l;j++)
{
ans=ans-*num[c[j]]+;
num[c[j]]--;
}
}
up[q.id]=ans-(q.r-q.l+); pl=q.l;
pr=q.r;
} for(int i=;i<=m;i++)
{
ll g=gcd(up[i],down[i]);
printf("%lld/%lld\n",up[i]/g,down[i]/g);
}
}
}

Luogu 1494 - 小Z的袜子 - [莫队算法模板题][分块]的更多相关文章

  1. bzoj 2308 小Z的袜子(莫队算法)

    小Z的袜子 [题目链接]小Z的袜子 [题目类型]莫队算法 &题解: 莫队算法第一题吧,建议先看这个理解算法,之后在参考这个就可以写出简洁的代码 我的比第2个少了一次sort,他的跑了1600m ...

  2. bzoj 2038 小Z的袜子 莫队算法

    题意 给你一个长度序列,有多组询问,每次询问(l,r)任选两个数相同的概率.n <= 50000,数小于等于n. 莫队算法裸题. 莫队算法:将序列分为根号n段,将询问排序,以L所在的块为第一关键 ...

  3. 【国家集训队2010】小Z的袜子[莫队算法]

    [莫队算法][国家集训队2010]小Z的袜子 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程, ...

  4. [日常摸鱼]bzoj2038[2009国家集训队]小Z的袜子-莫队算法

    今天来学了下莫队-这题应该就是这个算法的出处了 一篇别人的blog:https://www.cnblogs.com/Paul-Guderian/p/6933799.html 题意:一个序列,$m$次询 ...

  5. BZOJ 2038 小z的袜子 & 莫队算法(不就是个暴力么..)

    题意: 给一段序列,询问一个区间,求出区间中.....woc! 贴原题! 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过 ...

  6. 小Z的袜子 & 莫队

    莫队学习 & 小Z的袜子 引入 莫队 由莫涛巨佬提出,是一种离线算法 运用广泛 可以解决广大的离线区间询问题 莫队的历史 早在mt巨佬提出莫队之前 类似莫队的算法和莫队的思想已在Codefor ...

  7. BZOJ 2038 [2009国家集训队]小Z的袜子 莫队

    2038: [2009国家集训队]小Z的袜子(hose) 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Descriptionw ...

  8. BZOJ2038 [2009国家集训队]小Z的袜子 莫队+分块

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

  9. BZOJ 2038 小Z的袜子(hose) 莫队算法模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题目大意: 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中 ...

随机推荐

  1. MySQL 5.6新特性 -- Index Condition Pushdown

    Index Condition Pushdown(ICP)是针对mysql使用索引从表中检索行数据时的一种优化方法.   在没有ICP特性之前,存储引擎根据索引去基表查找并将数据返回给mysql se ...

  2. 【转】redis 消息队列发布订阅模式spring boot实现

    最近做项目的时候写到一个事件推送的场景.之前的实现方式是起job一直查询数据库,看看有没有最新的消息.这种方式非常的不优雅,反正我是不能忍,由于羡慕本身就依赖redis,刚好redis 也有消息队列的 ...

  3. Nuget 配置文件的位置

    最近在 Visual Studio 中使用 Nuget 时,发现总是连接代理服务器,忘了什么时候配置的了,找了半天没找到配置位置,最后发现在这个地方: %appdata%\NuGet 找到 NuGet ...

  4. java协变逆变,PECS

    public static void main(String[] args) { // Object <- Fruit <- Apple <- RedApple System.out ...

  5. Java 汇编代码

    https://shipilev.net/blog/2015/black-magic-method-dispatch/ https://github.com/shipilev/article-meth ...

  6. 【emWin】例程十七:窗口对象——Button

    介绍: 按钮小工具通常用作触摸屏的主要用户界面元素,本例程介绍按钮小工具的创建及使用方法. 触摸校准(上电可选择是否进入校准界面) 自绘按钮(通过回调函数来自行绘制各种形状的按钮) 设置按钮字体 设置 ...

  7. 【转】JS获取浏览器可视区域的尺寸

    from: http://www.xiaoboy.com/detail/1341545044.html 所谓可视区域是指能看得见的区域,即在浏览器中能看到页面的区域(高度与宽度).刚刚使用 docum ...

  8. 解决Xcode删除文件后missing file警告

    在用xcode开发的时候,删除不用的文件后, 编译的时候会有missing file的警告,原因是由于SVN或git造成的,有几种方法可以解决. 1.命令行进入missing file目录,然后运行 ...

  9. Nginx系列二:(Nginx Rewrite 规则、Nginx 防盗链、Nginx 动静分离、Nginx+keepalived 实现高可用)

    一.Nginx Rewrite 规则 1. Nginx rewrite规则 Rewrite规则含义就是某个URL重写成特定的URL(类似于Redirect),从某种意义上说为了美观或者对搜索引擎友好, ...

  10. 如何使用ABBYY FineReader 12将JPEG文件转换成可编辑文本

    日常工作中,经常会收到一些JPEG格式的图像文件,有时候还需要做一些修改,可是大家都知道JPEG格式的文件是无法修改的,必须转换成可编辑的格式,当然,现在市场上也应用而生了很多转换工具,相信大家都听说 ...