[bzoj2038][2009国家集训队]小Z的袜子(hose)——莫队算法
Brief Description
给定一个序列,您需要处理m个询问,每个询问形如[l,r],您需要回答在区间[l,r]中任意选取两个数相同的概率。
Algorithm Design
莫队算法入门题目。
这篇博客讲的不错
对于L,R的询问。设袜子的个数为\(cnt_i\)
那么答案即为$$\frac{\sum_i C_{cnt}^2}{\frac{(R-L+1)(R-L)}{2}}$$
其中\(C_n^m\)为组合数。
化简得:$$\frac{\sum_i cnt^2 -(R-L+1)}{(R-L+1)(R-L)}$$
所以这道题目的关键是求一个区间内每种颜色数目的平方和。
如果你知道了[L,R]的答案。你可以在O(1)的时间下得到[L,R-1]和[L,R+1]和[L-1,R]和[L+1,R]的答案的话。就可以使用莫队算法。
对于莫队算法我感觉就是暴力。只是预先知道了所有的询问。可以合理的组织计算每个询问的顺序以此来降低复杂度。要知道我们算完[L,R]的答案后现在要算[L',R']的答案。由于可以在O(1)的时间下得到[L,R-1]和[L,R+1]和[L-1,R]和[L+1,R]的答案.所以计算[L',R']的答案花的时间为|L-L'|+|R-R'|。如果把询问[L,R]看做平面上的点a(L,R).询问[L',R']看做点b(L',R')的话。那么时间开销就为两点的曼哈顿距离。所以对于每个询问看做一个点。我们要按一定顺序计算每个值。那开销就为曼哈顿距离的和。要计算到每个点。那么路径至少是一棵树。所以问题就变成了求二维平面的最小曼哈顿距离生成树。
关于二维平面最小曼哈顿距离生成树。感兴趣的可以参考胡泽聪大佬的这篇文章
这样只要顺着树边计算一次就ok了。可以证明时间复杂度为\(n* \sqrt n\)。
但是这种方法编程复杂度稍微高了一点。所以有一个比较优雅的替代品。那就是先对序列分块。然后对于所有询问按照L所在块的大小排序。如果一样再按照R排序。然后按照排序后的顺序计算。为什么这样计算就可以降低复杂度呢。
一、i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n0.5块,所以这一部分时间复杂度是n1.5。
二、i与i+1跨越一块,r最多变化n,由于有n0.5块,所以这一部分时间复杂度是n1.5
三、i与i+1在同一块内时变化不超过n0.5,跨越一块也不会超过2*n0.5,不妨看作是n0.5。由于有n个数,所以时间复杂度是n1.5
于是就变成了\(\Theta(n^{1.5})\)了。
Code
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
const int maxn = 50010;
#define ll long long
ll num[maxn], up[maxn], dw[maxn], ans, aa, bb, cc;
int col[maxn], pos[maxn];
struct qnode {
int l, r, id;
} qu[maxn];
bool cmp(qnode a, qnode b) {
if (pos[a.l] == pos[b.l])
return a.r < b.r;
else
return pos[a.l] < pos[b.l];
}
ll gcd(ll x, ll y) {
ll tp;
while ((tp = x % y)) {
x = y;
y = tp;
}
return y;
}
void update(int x, int d) {
ans -= num[col[x]] * num[col[x]];
num[col[x]] += d;
ans += num[col[x]] * num[col[x]];
}
int main() {
int n, m, bk, pl, pr, id;
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &m);
memset(num, 0, sizeof(num));
bk = ceil(sqrt(1.0 * n));
for (int i = 1; i <= n; i++) {
scanf("%d", &col[i]);
pos[i] = (i - 1) / bk;
}
for (int i = 0; i < m; i++) {
scanf("%d %d", &qu[i].l, &qu[i].r);
qu[i].id = i;
}
std::sort(qu, qu + m, cmp);
pl = 1, pr = 0;
ans = 0;
for (int i = 0; i < m; i++) {
id = qu[i].id;
if (qu[i].l == qu[i].r) {
up[id] = 0, dw[id] = 1;
continue;
}
if (pr < qu[i].r) {
for (int j = pr + 1; j <= qu[i].r; j++)
update(j, 1);
} else {
for (int j = pr; j > qu[i].r; j--)
update(j, -1);
}
pr = qu[i].r;
if (pl < qu[i].l) {
for (int j = pl; j < qu[i].l; j++)
update(j, -1);
} else {
for (int j = pl - 1; j >= qu[i].l; j--)
update(j, 1);
}
pl = qu[i].l;
aa = ans - qu[i].r + qu[i].l - 1;
bb = (ll)(qu[i].r - qu[i].l + 1) * (qu[i].r - qu[i].l);
cc = gcd(aa, bb);
aa /= cc, bb /= cc;
up[id] = aa, dw[id] = bb;
}
for (int i = 0; i < m; i++)
printf("%lld/%lld\n", up[i], dw[i]);
}
[bzoj2038][2009国家集训队]小Z的袜子(hose)——莫队算法的更多相关文章
- BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 3577 Solved: 1652[Subm ...
- [BZOJ2038] [2009国家集训队]小Z的袜子(hose) 莫队算法练习
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 10299 Solved: 4685[Sub ...
- BZOJ2038: [2009国家集训队]小Z的袜子(hose) 莫队算法
要使用莫队算法前提 ,已知[l,r]的答案,要能在logn或者O(1)的时间得到[l+1,r],[l-1,r],[l,r-1],[l,r+1],适用于一类不修改的查询 优美的替代品——分块将n个数分成 ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 7687 Solved: 3516[Subm ...
- 【bzoj2038】[2009国家集训队]小Z的袜子(hose) 莫队算法
原文地址:http://www.cnblogs.com/GXZlegend/p/6803860.html 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终 ...
- bzoj2038: [2009国家集训队]小Z的袜子(hose) [莫队]
Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...
- BZOJ2038[2009国家集训队]小Z的袜子(hose)——莫队
题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号 ...
- Bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队,分块,暴力
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 5763 Solved: 2660[Subm ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )
莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) --------------------------- ...
随机推荐
- Flask 中文手册 0.10 文档
Flask 中文手册 0.10 文档 欢迎使用 Flask 欢迎阅读 Flask 文档. 本文档分为几个部分.我推荐您先从 安装 开始,之后再浏览 快速入门 章节. 教程 比快速入门更详细地介绍了如何 ...
- MySQL☞order by与distinct
asc(升序,默认值)/desc(降序) 1.根据某一列的列值进行升序或者降序操作. select 列名 别名 from 表名 order by 列名 asc/desc 2.根据多个列值进行排序 s ...
- 基于Vue、web3的以太坊项目开发及交易内幕初探 错误解决总结
基于Vue.web3的以太坊项目开发及交易内幕初探 本文通过宏观和微观两个层面窥探以太坊底层执行逻辑. 宏观层面描述创建并运行一个小型带钱包的发币APP的过程,微观层面是顺藤摸瓜从http api深入 ...
- struts2中的action为什么要继承ActionSupport类,不继承也可以,有什么好处?
简单来说,有很多相关的方法都加载进来,你直接调用就行了,而且在安全上和稳定性上做了很好的处理 实际上继承ActionSupport之后 就等同于实现了很多接口 Action,Validateable, ...
- 文件名的查找——find
查找文件!!! 命令格式:find [PATH] [option] [action] 一.参数1——与时间有关的参数 -atime.-ctime.-mtime -mtime n:在n天之前的“一天之内 ...
- Python中enumerate函数用法详解
enumerate函数用于遍历序列中的元素以及它们的下标,多用于在for循环中得到计数,enumerate参数为可遍历的变量,如 字符串,列表等 一般情况下对一个列表或数组既要遍历索引又要遍历元素时, ...
- Android隐藏键盘
今天接到的任务是在验证码输入框中加入键盘监听事件,需要点击Enter实现登录,这个比较好实现,但是在登录时,键盘并没有隐藏掉,看上去很别扭,因此,百度了一堆方法,但是都无济于事,最后找到了一个,如下, ...
- Java基础——IO
一.概述 I/O,Input/Output输入输出.输入机制比如读取文件数据.用户键盘输入等,输出,比如将数据输出到磁盘等. Java的IO是以流(Stream)为基础的. 流的叫法十分形象,你可以想 ...
- [Leetcode] word break 拆分词语
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separa ...
- 【COGS 1534】 [NEERC 2004]K小数 &&【COGS 930】 [河南省队2012] 找第k小的数 可持久化01Trie
板子题,只是记得负数加fix最方便 #include <cstdio> ,N=; namespace FIFO { <<],*S=B,*T=B; #define getc() ...