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)——莫队算法的更多相关文章

  1. BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 3577  Solved: 1652[Subm ...

  2. [BZOJ2038] [2009国家集训队]小Z的袜子(hose) 莫队算法练习

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 10299  Solved: 4685[Sub ...

  3. BZOJ2038: [2009国家集训队]小Z的袜子(hose) 莫队算法

    要使用莫队算法前提 ,已知[l,r]的答案,要能在logn或者O(1)的时间得到[l+1,r],[l-1,r],[l,r-1],[l,r+1],适用于一类不修改的查询 优美的替代品——分块将n个数分成 ...

  4. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Subm ...

  5. 【bzoj2038】[2009国家集训队]小Z的袜子(hose) 莫队算法

    原文地址:http://www.cnblogs.com/GXZlegend/p/6803860.html 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终 ...

  6. bzoj2038: [2009国家集训队]小Z的袜子(hose) [莫队]

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

  7. BZOJ2038[2009国家集训队]小Z的袜子(hose)——莫队

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

  8. Bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队,分块,暴力

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 5763  Solved: 2660[Subm ...

  9. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )

    莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) --------------------------- ...

随机推荐

  1. 新手入门Sqlalchemy

    此文已由作者尤炳棋授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 入职考拉半年多,一直在从事KLQA平台的开发,KLQA平台后端是用基于python的flask框架搭建的.F ...

  2. Linux 文件与目录管理命令

    处理目录的常用命令 常见的处理目录的命令: ls: 列出目录 cd:切换目录 pwd:显示目前的目录 mkdir:创建一个新的目录,语法:mkdir [-mp] 目录名称 -m :配置文件的权限 -p ...

  3. java---解析XML文件,通过反射动态将XML内容封装到一个类中

    本博客讲的XML解析,使用的是dom4j. 首先建立一个maven项目,在dom.xml中引入相应的dom4j的版本.作者下载的是热度很高的1.6.1版本.maven的使用在这里不做详细讲解. 引入成 ...

  4. asm和file system之间数据文件的转换

    How to move a datafile from a file system to ASMMoving a datafile from the file system can be achive ...

  5. 目标检测之Faster-RCNN的pytorch代码详解(模型准备篇)

    十月一的假期转眼就结束了,这个假期带女朋友到处玩了玩,虽然经济仿佛要陷入危机,不过没关系,要是吃不上饭就看书,吃精神粮食也不错,哈哈!开个玩笑,是要收收心好好干活了,继续写Faster-RCNN的代码 ...

  6. 【集训试题】exam 信心考 最小割

    题意概述: 有N个人,A,B两个考场.如果学生i在A考场,总信心值增加xi:如果学生i在B考场,总信心值增加yi.其中还有m对好友,当第i对好友的两个人都在A考场时,总信心值增加ai:如果两人都在B考 ...

  7. [译]10个有关SCP的命令

    原文来源: https://www.tecmint.com/scp-commands-examples/ 基本语法 scp source_file_name username@destination_ ...

  8. HDU 1445 Ride to School

    http://acm.hdu.edu.cn/showproblem.php?pid=1445 Problem Description Many graduate students of Peking ...

  9. IDEA里面添加lombok插件,编写简略风格Java代码

    在 java平台上,lombok 提供了简单的注解的形式来帮助我们消除一些必须有但看起来很臃肿的代码, 比如属性的get/set,及对象的toString等方法,特别是相对于 POJO; 关于lomb ...

  10. 【Python】PYTHON九九乘法表

    python2.7 for i in range(1,10):  for j in range(1,i+1):    print j,'x',i,'=',j*i,'\t',  print '\n'pr ...