【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 ...
随机推荐
- [leetcode]_Roman to Integer
题目:给定一个罗马数字串,转换为一个整数. 一开始没理解,以为是string to int.后来理解:罗马数字与阿拉伯数字的映射关系,见下图: 至此,题目的意思才掌握明白,用程序模拟这张表. 无可置否 ...
- Oracle删除表主键语句
删除无名主键语句: SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME = '表名'; ALTER TABLE 表名 DROP CONSTRAINT 主键 ...
- Android开发环境下关于如何导出手机通讯录数据库【Written By KillerLegend】
首先度Linux中的权限(Permissions)进行一些说明: permissions一共有10个符号位,[- --- --- ---],在这里我们从左至右由0开始编号,各个符号位的编号分别为0,1 ...
- 合并果子 (codevs 1063) 题解
[问题描述] 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和 ...
- Python 初学(一) 标识符
Python 标识符 在python里,标识符由字母.数字.下划线组成: python中的标识符是区分大小写的: 1)以单下划线开头(_foo)的代表不能直接访问的类属性,需要通过类提供的接口进行访问 ...
- SQL Server 一些关键字详解(一)
1.CROSS APPLY 和OUTER APPLY MSDN解释如下(个人理解不是很清晰): 使用 APPLY 运算符可以为实现查询操作的外部表表达式返回的每个行调用表值函数.表值函数作为右输入,外 ...
- 应聘复习基础笔记1:网络编程之TCP与UDP的优缺点,TCP三次握手、四次挥手、传输窗口控制、存在问题
重要性:必考 一.TCP与UDP的优缺点 ①TCP---传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供 ...
- ListView的动态刷新问题——用notifyDataSetChanged没作用
也许很多开发的朋友,尤其是Android初学者(笔者也是个初学者),在动态刷新ListView时,使用notifyDataSetChanged并没有起到作用.有时会被困扰得很痛苦. 其实,在使用not ...
- MongoDB 数据类型
MongoDB支持许多数据类型的列表下面给出: String : 这是最常用的数据类型来存储数据.在MongoDB中的字符串必须是有效的UTF-8. Integer : 这种类型是用来存储一个数值.整 ...
- Android开发随笔之ScrollView嵌套GridView[ 转]
今天在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全,为了解决这个问题查了N多资料,某个谷歌的 ...