http://www.lydsy.com/JudgeOnline/problem.php?id=2038

学了下莫队,挺神的orzzzz

首先推公式的话很简单吧。。。

看的题解是从http://foreseeable97.logdown.com/posts/158522-233333来的

对于查询$[l,r]$

$$ans=\frac{\sum \dbinom{x_i}{2}}{\dbinom{r-l+1}{2}}$$

其中$x_i$表示当前区间颜色为i的出现次数

这个还用解释么。。。。

然后我们化简$\sum \dbinom{x_i}{2}$

$$\sum \dbinom{x_i}{2} = \sum x(x-1)/2 = \frac{1}{2} (\sum x^2 - \sum x) = \frac{1}{2} ((\sum x^2) - (r-l+1)) $$

最后一步是因为$\sum x=r-l+1$所以化简。

那么对于区间$[l, r]$,我们只需要找到能快速计算出$\sum x^2$的做法即可。

然后神转化!

对于这一类问题:比如询问序列中区间$[l,r]$的什么东西,如果我们已经知道了$[l,r]$的答案,那么就能在$O(1)$或$O(lgn)$的时间得到$[l,r+1]$或$[l-1,r]$的答案,而且允许离线,那我们可能用莫队算法优化!

莫队算法orz可以实现$O(n^{1.5})$解决(当然不是固定的复杂度,但是一定有$n^{0.5}$在里边,其实莫队算法实质=分块?

回到本题:

首先先看如何更新答案

考虑我们得到了$[l, r]$的答案,假设$sum = \sum x^2$,那么本题中,有

当更新$[l, r+1]$的答案时

$$sum = sum - x[r+1]^2 + (x[r+1]+1)^2$$

很好理解吧。。。

那么$[l, r-1],[l-1, r],[l+1, r]$之类的应该很好懂吧。。

所以这样做每一次从一个询问区间转到另一个询问区间的时间复杂度为$O(|l_{i-1}-l_i|+|r_{i-1}-r_i|)$

那么其实我们已经能够写出暴力了。。。

可是复杂度QAQtle是肯定的。。。(但是奇葩的是,这数据略弱,将long long改成unsigned int,然后按询问区间左端点排序,就能6s a掉。。。233

现在来分析这些询问。

要完成最小化$|l_{i-1}-l_i|+|r_{i-1}-r_i|$的目标,我们来将所有区间放到坐标系上看(l和r随便一个作为x和y轴啦)

然后可以发现其实这就是曼哈顿距离,,,所以要最小化这个目标,其实求的就是最小曼哈顿距离生成树QAQ可是连边的话复杂度已经$O(n^2)$...

(当然有一种快速算法,叫啥:笛卡尔树+LCA优化rmq 。。。。有待补坑。。。

所以一个叫莫涛的神犇发明了这个莫队算法,分块!

解法:

我们将询问的区间$[1, n]$分成$n^{0.5}$个块,每一个块都包含$n^{0.5}$个下标$l$,将每个询问的$l$放到对应块中,排序的时候先看是否$l$属于同一个块,如果是,比较$r$,否则比较块的位置。

然后再暴力!这样成功变成$O(n^{1.5})$!

至于为什么,请耐心往下看。。

首先考虑一下在块中,$r$移动了多少次。

因为$r$是单增,所以$r$最多移动$O(n)$次。因为有$n^{0.5}$个块,所以所有块中r最多移动$O(n^{1.5})$

再来考虑$r$从一个块移动到另一个块所需要的时间:$O(n^{0.5})$个块,每次最多$O(n)$次,因此复杂度是$O(n^{1.5})$

然后考虑$l$

在每一个块中,每一个$l$最多要移动$O(n^{0.5})$次,所有询问中有$n$个l,所以最坏复杂度是$O(n^{1.5})$

考虑$l$从一个块移动到另一个块所需要时间:长度相差最多$O(n^{0.5})$,有$O(n^{0.5})$个块,因而复杂度是$O(n)$

那么总体复杂度为$O(n^{1.5})$

神吧~orz

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef unsigned int ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } const int N=50005;
struct dat { int l, r, id; }q[N];
int a[N], n, m, blc[N];
ll sum, x[N], y[N], s[N]; inline ll gcd(const ll &a, const ll &b) { return b?gcd(b, a%b):a; }
inline bool cmp(const dat &a, const dat &b) { return blc[a.l]==blc[b.l]?a.r<b.r:a.l<b.l; }
inline void fix(const int &x, const int &f) {
sum-=s[x]*s[x];
s[x]+=f;
sum+=s[x]*s[x];
}
void init() {
int sz=sqrt(0.5+n), now=0, tot=0;
for1(i, 1, n) {
++now;
blc[i]=tot;
if(now==sz) now=0, ++tot;
}
sort(q+1, q+1+m, cmp);
}
int main() {
read(n); read(m);
for1(i, 1, n) read(a[i]);
for1(i, 1, m) read(q[i].l), read(q[i].r), q[i].id=i;
init();
int l=q[1].l, r=q[1].r;
for1(i, l, r) fix(a[i], 1);
x[q[1].id]=sum-(r-l+1);
y[q[1].id]=(r-l+1)*(r-l);
for1(i, 2, m) {
int xl=q[i].l, xr=q[i].r, id=q[i].id;
ll rg=(xr-xl+1);
while(l<xl) fix(a[l++], -1);
while(l>xl) fix(a[--l], 1);
while(r<xr) fix(a[++r], 1);
while(r>xr) fix(a[r--], -1);
x[id]=sum-rg;
y[id]=rg*(rg-1);
}
for1(i, 1, m) { if(x[i]<=0 || y[i]<=0) { puts("0/1"); continue; } ll g=gcd(x[i], y[i]); printf("%u/%u\n", x[i]/g, y[i]/g); }
return 0;
}

  


Description

作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……
具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

Input

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

Output

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

Sample Input

6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6

Sample Output

2/5
0/1
1/1
4/15
【样例解释】
询问1:共C(5,2)=10种可能,其中抽出两个2有1种可能,抽出两个3有3种可能,概率为(1+3)/10=4/10=2/5。
询问2:共C(3,2)=3种可能,无法抽到颜色相同的袜子,概率为0/3=0/1。
询问3:共C(3,2)=3种可能,均为抽出两个3,概率为3/3=1/1。
注:上述C(a, b)表示组合数,组合数C(a, b)等价于在a个不同的物品中选取b个的选取方案数。
【数据规模和约定】
30%的数据中 N,M ≤ 5000;
60%的数据中 N,M ≤ 25000;
100%的数据中 N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

HINT

 

Source

【BZOJ】2038: [2009国家集训队]小Z的袜子(hose)(组合计数+概率+莫队算法+分块)的更多相关文章

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

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

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

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

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

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

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

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

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

    分块大法好 2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 2938  Solved: 13 ...

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

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

  7. 洛谷 P1494 BZOJ 2038 [2009国家集训队]小Z的袜子(hose)

    //洛谷题面字体.排版我向来喜欢,却还没收录这道如此有名的题,BZOJ的题面字体太那啥啦,清橙的题面有了缩进,小标题却和正文字体一致,找个好看的题面咋这么难呐………… //2019年3月23日23:0 ...

  8. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)&&莫对算法

    这里跟曼哈顿最小生成树没有太大的关系. 时间复杂度证明: [BZOJ2038 小Z的袜子 AC代码] 排序方式: 第一关键字:l所在的块: 第二关键字:r从小到大. #include<cstdi ...

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

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

  10. bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2038 [题意] 给定一个有颜色的序列,回答若干个询问:区间内任选两个颜色相同的概率. ...

随机推荐

  1. System.SysUtils.TMarshaller 与 System.TMarshal

    转自:http://www.cnblogs.com/del/archive/2013/06/10/3130974.html TMarshaller(结构) 基于 TMarshal(是有一大堆的 cla ...

  2. zookeeper 用法和日常运维

    本文以ZooKeeper3.4.3版本的官方指南为基础:http://zookeeper.apache.org/doc/r3.4.3/zookeeperAdmin.html,补充一些作者运维实践中的要 ...

  3. ssh连接慢的问题的解决?

    <1>群中同学遇到的问题,我之前在uuwatch也遇到了同样的问题? 问个问题师兄们 突然之间 公司服务器连接很慢 连一个shell需要10几秒钟 服务器就在公司全是内网服务器, 我也不知 ...

  4. js 函数声明方式以及javascript的历史

    1.function  xx(){} 2.匿名方式   window.onload=function(){dslfjdslfkjdslf}; 3.动态方式  var demo=new Function ...

  5. poj1166

    爆搜就可以过,不过我用了迭代加深. 注意每个操作最多进行4次 #include <cstdio> #include <cstdlib> using namespace std; ...

  6. Java for LeetCode 202 Happy Number

    Write an algorithm to determine if a number is "happy". A happy number is a number defined ...

  7. Js数组里删除指定的元素(不是指定的位置)

    转载自:http://my.oschina.net/zh119893/blog/265964 之前一直是做后端的,从来也没有写过js,但是却一直想学学,也只是基于兴趣而已!现在到了这个公司,确实大量的 ...

  8. .tar.bz2文件解压命令

    从网络上下载到的源码包, 最常见的是 .tar.gz 包, 还有一部分是 .tar.bz2包 要解压很简单 : .tar.gz     格式解压为          tar   -zxvf   xx. ...

  9. How to Optimize Battery Health?

    1. click on the battery icon from taskbar next to the date and time. 2. click "More power optio ...

  10. Maximum sum(poj 2479)

    题意:给一段数列,将这个数列分成两部分,使两部分的最大子段和的和最大,输出和 /* 看数据没想到是(O)n的算法,求出从前向后的最大子段和和从后向前的最大子段和, 然后枚举断点. 第一次提交不小心折在 ...