【BZOJ】【2038】小Z的袜子
填个坑吧,学习了莫队算法。我也忘记是看的哪位大牛的博客&代码学习的了T_T,如果您发现了的话请私信我,我会注明学自您的代码。
另外感谢@PoPoQQQ大神
好,进入正文,莫队算法,也算是一种暴力吧,从某种意义上来说……是一种对暴力的强大优化= =
对于区间的莫队是基于【分块】的思想,这一点有些类似求离散对数的【大步小步算法】。
首先我们来考虑一个赤果果的暴力算法:对于每个询问,从L到R枚举一遍,统计每种袜子出现的次数,然后用组合数学的方法算出抽到两只相同袜子的方案数,和所有抽取袜子的总方案数。(至于求GCD然后约分什么的应该都懂的)
实际上,我们在进行暴力枚举的时候,有很多区间在不同的询问中计算了多次,而实际上这些已经进行过的计算完全是可以尽可能地进行再次利用的!两个相差不大的询问的结果相似度是很高的,我们完全可以在进行完一个[l,r]的计算后,进行少许更改,快速转移到[l',r']。
这就可以通过对询问顺序进行适当调整来实现:没错!排序!
那么问题来了:要按照什么样的顺序来排序呢?莫队发明的莫队算法提出了一种很科学的解决方案:分块。
把长度为N的序列分为sqrt(N)块,每块大小为sqrt(N),然后按 l 所在块的先后顺序排,l 在同一块内的按r的递增顺序排。(为什么这样分?根据基本不等式等等等等可以推出这样复杂度最低啊!当然如果带修改还会有别的分法)
排好序了,接下来就好办啦~先算出来这个块第一个询问的答案,然后不断执行-1+1调整区间。详细内容看代码注释吧~
//BZOJ 2038
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
const int N=;
typedef long long LL; int n,sqr;
struct qes{
LL t,l,r;
bool operator < (const qes &a) const{
return (l/sqr)<(a.l/sqr) || (l/sqr)==(a.l/sqr) && r<a.r;
}//第一个条件是按 l 所在块排,第二个条件是按 r 单调增
}q[N]; LL gcd(LL a,LL b){
if (!b) return a;
else return gcd(b,a%b);
} LL Ans[N][]; int m,c[N],cnt[N]; int main(){
#ifndef ONLINE_JUDGE
freopen("file.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
sqr=int(sqrt(n));
F(i,,n) scanf("%d",&c[i]);
F(i,,m){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].t=i;
}
sort(q+,q+m+); LL rec;
int l,r;
F(i,,m){
if (i== || q[i].l/sqr != q[i-].l/sqr){
//如果是一个新的块就重新计算(将这个块第一个询问结果作为当前块所有询问的基底)
F(j,,n) cnt[j]=;
l=q[i].l; r=q[i].r;
F(j,l,r) ++cnt[c[j]];//本询问区间内计数统计
rec=;//rec表示选出相同袜子的方案数
F(j,,n) rec+=(LL)(cnt[j])*(LL)(cnt[j]-);
} //这三个for循环是 -1 +1 更新本节点的值
for(;r<q[i].r;++r){
//对于l在同一个块中的q,是按r单调增的顺序排序了的……
int s=c[r+];
rec-=(LL)(cnt[s])*(LL)(cnt[s]-);
++cnt[s];
rec+=(LL)(cnt[s])*(LL)(cnt[s]-);
//重新计算当前区间的答案
//比如原来是[2,3,3]现在变成了[2,3,3,3]那么就要减去颜色为3的袜子对答案的贡献
//再加上数量增加了1以后 它对答案的贡献
}
for(;l<q[i].l;++l){
//但是在同一块中,l并不一定是单调增的,所以会有向左右两个方向的调整
//这是向右
int s=c[l];
rec-=(LL)(cnt[s])*(LL)(cnt[s]-);
--cnt[s];
rec+=(LL)(cnt[s])*(LL)(cnt[s]-);
}
for(;l>q[i].l;--l){
//这是向左
int s=c[l-];
rec-=(LL)(cnt[s])*(LL)(cnt[s]-);
++cnt[s];
rec+=(LL)(cnt[s])*(LL)(cnt[s]-);
}
if (rec){
LL ret=gcd(rec,(LL)(r-l+)*(LL)(r-l));
Ans[q[i].t][]=rec/ret;
Ans[q[i].t][]=((LL)(r-l+)*(LL)(r-l))/ret;
} else Ans[q[i].t][]=,Ans[q[i].t][]=;//按询问顺序保存&输出
}
F(i,,m) printf("%lld/%lld\n",Ans[i][],Ans[i][]);
return ;
}
【BZOJ】【2038】小Z的袜子的更多相关文章
- bzoj 2038 小Z的袜子(hose)(莫队算法)
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 11542 Solved: 5166[Sub ...
- (原创)BZOJ 2038 小Z的袜子(hose) 莫队入门题+分块
I - 小Z的袜子(hose) 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z ...
- BZOJ - 2038 小Z的袜子(普通莫队)
题目链接:小Z的袜子 题意:$n$只袜子,$m$个询问,每次回答有多大概率在$[L,R]$区间内抽到两只颜色相同的袜子 思路:普通莫队,如果两个询问左端点在一个块内,则按询问右端点排序,否则按照所在块 ...
- BZOJ 2038 小z的袜子 & 莫队算法(不就是个暴力么..)
题意: 给一段序列,询问一个区间,求出区间中.....woc! 贴原题! 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过 ...
- BZOJ 2038 小Z的袜子(hose) 莫队算法模板题
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题目大意: 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中 ...
- BZOJ 2038 小z的袜子(莫队)
Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...
- [BZOJ 2038]小Z的袜子
传送门:BZOJ 2038 题意很明确,是在给定的区间内任意选取两个数,求选到两个相同的数的概率. 所以我们得首先统计在给定的区间内,相同的数对有多少对,那么这里就使用到了莫队算法.如果对莫队算法还不 ...
- BZOJ 2038 小Z的袜子(hose)(分组)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2038 题意:给出n个袜子.m个询问,每个询问一个区间[L,R],询问这个区间中任意拿出两 ...
- bzoj 2038 小z的袜子 莫队例题
莫队,利用可以快速地通过一个问题的答案得到另一问题的答案这一特性,合理地组织问题的求解顺序,将已解决的问题帮助解决当前问题,来优化时间复杂度. 典型用法:处理静态(无修改)离线区间查询问题. 线段树也 ...
- [bzoj] 2038 小Z的袜子(hose) || 莫队
原题 给出一个序列,求给定[l,r]内有任意取两个数,有多大概率是一样的 简单的莫队,每次+-当前区间里有的这个颜色的袜子的个数,最后除以(r-l+1)*(r-l)/2即可. 记得约分. #inclu ...
随机推荐
- Uva12504 Updating a Dictonary
这道题难度不大,主要是考察熟练运用C++的容器,字符串等操作. 另外注意特殊情况是否需要特殊处理.即当一个字典为空时,无论另一个字典是否有值,输出的结果都为No Change,这点需要注意一下. 另外 ...
- 【转】IE11的变化
1.navigator.userAgent中不再包含“MSIE”关键字 2.用javascript的判断是否是IE11的方法是: var isIE11 = (sUserAgent.toLowerCas ...
- luigi学习3-使用luigid
--local-scheduler的方式只适用于开发调试阶段,当你真正要把程序部署到一个产品时,我们推荐使用luigid服务. 使用luigid服务不但能提供锁服务(防止一个任务被多个进程重复执行), ...
- 区间 (vijos 1439) 题解
[问题描述] 现给定n个闭区间[ai,bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排 ...
- 使用c#检测文件正在被那个进程占用 判断文件是否被占用的两种方法
C# 判断文件是否被占用的三种方法 using System.IO; using System.Runtime.InteropServices; [DllImport("kernel32.d ...
- Oracle自用脚本(持续更新)
--查询Oracle正在执行的sql语句及执行该语句的用户 SELECT b.sid oracleID, b.username 登录Oracle用户名, b.serial#, spid 操作系统ID, ...
- jqueryMobile应用第一课《构建跨平台APP:jQuery Mobile移动应用实战》连载一(Hello World)
有人说每个程序员都曾经有过改变世界的梦想,笔者认为,这与程序员年轻时编写的第一个程序有着莫大的关系.简简单单的一句“hello world”让年轻的心开始相信梦想,用一种低调的壮志凌云向世界展示自己的 ...
- .net 的生成操作
生成操作(BuildAction) 属性:BuildAction 属性指示 Visual Studio .NET 在执行生成时对文件执行的操作. BuildAction 可以具有以下几个值之一: 无( ...
- Go返回参数命名
Go语言中可以为返回值定义名称.代码实例: package main import "fmt" func add1(a int, b int) int { return a + b ...
- Mac下如何显示隐藏文件/文件夹_百度经验
在应用程序里打开终端, cd 你的文件夹名 ls -a 即可显示该文件夹下的所有隐藏文件 如果你想打开整个系统的隐藏文件可以在终端下输入以下命令: defaults write com.apple ...