初识莫队——小Z的袜子
以前一直觉得莫队是多么高大上的一种算法,然而仔细看了下发现其实并不复杂,实质上就是技巧性的暴力美学。
在我看来莫队是一种分块排序后降低复杂度的算法,当答案可以通过左右端点一个一个移动维护出来的时候就可以使用莫队了。
比如给你4个区间
(1, 2)
(99, 100)
(3, 4)
(101, 102)
如果你是傻傻的按照给定的顺序去移动左右端点,那就是先计算出(1,2)区间的值,然后左端点先从1移动到99,右端点从2移动到100,计算完(99,100)区间内的值,又哼哧哼哧的左端点从99移回3,右端点从100移回4,计算完(3,4)后又移动到(101,102),显然这样实在是太蠢了。
正常人都应该想到,那我把计算顺序改成(1,2)(3,4)(99,100)(101,102)不就行了,但是因为区间是二维的,简单的排序似乎是行不通的(通过lhs或者rhs来排序似乎都不太好)
莫队为我们提供了一个排序方法,假设有Q个询问,区间范围是1~N,那么可以对左端点分块,分成根号N块,这样就先把不同块的左端点排好序了,接下来同一块的询问根据右端点排序,这样就形成了一个(比较科学)的序列,可以使左右端点移动的距离变小,变相减小了复杂度。
实际上莫队就是一个科学的二维数组排序方法嘛
然后对于这道题因为是求概率,每次如果都维护一个分数很困难,所以选择每次维护分子和分母,这样这个概率公式就很好求了,分母只与区间长度有关,分子就是(每种袜子数目*(每种袜子数目-1))然后求和,化简后发现只要求(每种袜子数目)的平方的和就可以了,最后求一下gcd把分数表示成最简形式
#include <iostream>
#include <string.h>
#include <cstdio>
#include <vector>
#include <map>
#include <math.h>
#include <string>
#include <algorithm>
#include <time.h> #define SIGMA_SIZE 26
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define goe(i, a, b) for(int i=a; i<=b; i++)
#define go(i, a, b) for(int i = a; i < b; i++);
#pragma warning ( disable : 4996 ) using namespace std;
typedef long long LL;
inline LL LMax(LL a,LL b) { return a>b?a:b; }
inline LL LMin(LL a,LL b) { return a>b?b:a; }
inline LL lgcd( LL a, LL b ) { return b==?a:lgcd(b,a%b); }
inline LL llcm( LL a, LL b ) { return a/lgcd(a,b)*b; } //a*b = gcd*lcm
inline int Max(int a,int b) { return a>b?a:b; }
inline int Min(int a,int b) { return a>b?b:a; }
inline int gcd( int a, int b ) { return b==?a:gcd(b,a%b); }
inline int lcm( int a, int b ) { return a/gcd(a,b)*b; } //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = ;
const double eps = 1e-;
const int inf = 0x3f3f3f3f;
const int maxk = 5e4+;
const int maxn = 3e4+; int belong[maxk], wazi[maxk];
int N, M, unit;
LL ans, cnt[maxk], fina[maxk], finb[maxk];
struct query {
int lhs, rhs, id;
LL a, b; //分子和分母
}q[maxk]; bool cmp(const query& a, const query& b)
{
if (belong[a.lhs] == belong[b.lhs]) return a.rhs < b.rhs;
return a.lhs < b.lhs;
} void revise( int x, int d )
{
//ans先减去以前的贡献再加上现在的贡献
ans -= cnt[wazi[x]]*cnt[wazi[x]];
cnt[wazi[x]] += d;
ans += cnt[wazi[x]]*cnt[wazi[x]];
} void read()
{
scanf("%d %d", &N, &M); unit = sqrt(N); goe(i, , N) { scanf("%d", &wazi[i]); belong[i] = i/unit+; }
goe(i, , M) { scanf("%d %d", &q[i].lhs, &q[i].rhs); q[i].id = i; }
sort(q+, q++M, cmp); } int main()
{
read(); int l = , r = ;
ans = ; goe(i, , M)
{
//如果是减操作,则先要执行revise,
//注意顺序
while(l < q[i].lhs) { revise(l, -); l++; }
while(l > q[i].lhs) { l--; revise(l, ); }
while(r < q[i].rhs) { r++; revise(r, ); }
while(r > q[i].rhs) { revise(r, -); r--; } if ( q[i].lhs == q[i].rhs ) { q[i].a = ; q[i].b = ; continue; }
q[i].a = ans - (q[i].rhs - q[i].lhs + );
q[i].b = (LL)*(q[i].rhs - q[i].lhs)*(q[i].rhs - q[i].lhs + ); LL Gcd = lgcd(q[i].a, q[i].b);
q[i].a /= Gcd;
q[i].b /= Gcd;
} goe(i, , M)
{
fina[q[i].id] = q[i].a;
finb[q[i].id] = q[i].b;
} goe(i, , M)
printf("%lld/%lld\n", fina[i], finb[i]); return ;
}
待修改的莫队,这就有点难受了,原先的二维区间变成了三维,加了一个时间维度(怎么感觉怪怪的),大意就是原先每个结构体多存储一个了时间变量,修改操作也通过时间变量储存,并且通过change这一数据结构将一系列修改的数据存储下来(即能通过时间确定修改的值,就像能操纵时间,随时可以通过时间还原原来的序列或者变化成修改后的序列),然后就是在原始莫队的基础上加上一个时间维度的移动,不得不说这个算法真是朴素而美妙...
HYSBZ 2120 数颜色---模板题
#include <iostream>
#include <string.h>
#include <cstdio>
#include <vector>
#include <map>
#include <math.h>
#include <string>
#include <algorithm>
#include <time.h> #define SIGMA_SIZE 26
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define foe(i, a, b) for(int i=a; i<=b; i++)
#define fo(i, a, b) for(int i = a; i < b; i++);
#pragma warning ( disable : 4996 ) using namespace std;
typedef long long LL;
inline LL LMax(LL a,LL b) { return a>b?a:b; }
inline LL LMin(LL a,LL b) { return a>b?b:a; }
inline LL lgcd( LL a, LL b ) { return b==?a:lgcd(b,a%b); }
inline LL llcm( LL a, LL b ) { return a/lgcd(a,b)*b; } //a*b = gcd*lcm
inline int Max(int a,int b) { return a>b?a:b; }
inline int Min(int a,int b) { return a>b?b:a; }
inline int gcd( int a, int b ) { return b==?a:gcd(b,a%b); }
inline int lcm( int a, int b ) { return a/gcd(a,b)*b; } //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = ;
const double eps = 1e-;
const int inf = 0x3f3f3f3f;
const int maxk = 1e6+;
const int maxn = 1e4+; int belong[maxn], num[maxn], now[maxn], fin[maxn];
int N, Q, unit, l, r;
int t, T, Time, ans;
int cnt[maxk]; struct query {
int lhs, rhs, tim, id;
query() {}
query(int l, int r, int t, int i)
: lhs(l), rhs(r), tim(t), id(i) {} }q[maxn]; // pos表示修改的位置,new表示修改后的值,Old表示修改前的值
struct change {
int pos, New, Old;
change() {}
change(int p, int n, int o)
: pos(p), New(n), Old(o) {}
}c[maxn]; bool cmp(const query& a, const query& b)
{
if (belong[a.lhs != b.lhs]) return a.lhs < b.lhs;
if (belong[a.rhs != b.rhs]) return a.rhs < b.rhs;
return a.tim < b.tim;
} void read()
{
//最优分块策略不再是根号
scanf("%d %d", &N, &Q); unit = pow((double)N, (double)0.666666);
foe(i, , N) { scanf("%d", &num[i]); now[i] = num[i]; belong[i] = i/unit+; } char str[];
int x, y; t = T = ;
foe(i, , Q)
{
scanf("%s %d %d", str, &x, &y);
if (str[] == 'Q') q[++t] = query(x, y, T, t);
if (str[] == 'R') { c[++T] = change(x, y, now[x]); now[x] = y; }
}
sort(q+, q+t+, cmp);
} void revise(int x, int d)
{
cnt[x] += d;
if (d > )
ans += (cnt[x] == ); //只有从0加到1才会增加一种颜色数量
if (d < )
ans -= (cnt[x] == );
} void reviseT(int x, int d)
{
if ( x >= l && x <= r )
{
revise(d, );
revise(num[x], -);
}
num[x] = d;
} int main()
{
read(); l = ; r = ; Time = ;
foe(i, , t)
{
//若修改时间小于tim,则要添加新的修改
while(Time < q[i].tim) { Time++; reviseT(c[Time].pos, c[Time].New); }
//若time大于tim,则还原老修改
while(Time > q[i].tim) { reviseT(c[Time].pos, c[Time].Old); Time--; } while(l < q[i].lhs) { revise(num[l], -); l++; }
while(l > q[i].lhs) { l--; revise(num[l], ); }
while(r < q[i].rhs) { r++; revise(num[r], ); }
while(r > q[i].rhs) { revise(num[r], -); r--; } fin[q[i].id] = ans; } foe(i, , t)
printf("%d\n", fin[i]); return ;
}
初识莫队——小Z的袜子的更多相关文章
- 莫队-小Z的袜子
----普通莫队 首先清楚概率怎么求假设我们要求从区间l到r中拿出一对袜子的概率sum[i]为第i种袜子在l到r中的数量 $$\frac{\sum_{i=l}^{r} {[sum[i] \times ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 7687 Solved: 3516[Subm ...
- 莫队算法 2038: [2009国家集训队]小Z的袜子(hose)
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2038 2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 ...
- BZOJ-2038 小Z的袜子(hose) 莫队算法
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MB Submit: 5573 Solved: 2568 [Subm ...
- BZOJ 2038 [2009国家集训队]小Z的袜子 莫队
2038: [2009国家集训队]小Z的袜子(hose) 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Descriptionw ...
- Bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队,分块,暴力
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 5763 Solved: 2660[Subm ...
- BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 3577 Solved: 1652[Subm ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )
莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) --------------------------- ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&&学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 9894 Solved: 4561[Subm ...
随机推荐
- 一个切图仔的 CSS 笔记
1,flexbox~注意,设为 Flex 布局以后,子元素的float.clear和vertical-align属性将失效. 在ios8上要加上前缀 display: -webkit-box; dis ...
- Linux g++
Usage: g++ [options] file...Options: -pass-exit-codes Exit with highest error code from a p ...
- day21 生成器,列表解析,三元表达式
Python之路,Day9 = Python基础9 判断可迭代对象和迭代器 from collections import Iterable, Iterator # 导入模块功能,用来判断对象是否为I ...
- thinkphp 三元运算
模板可以支持三元运算符,例如: {$status?'正常':'错误'} {$info['status']?$info['msg']:$info['error']} 注意:三元运算符中暂时不支持点语法. ...
- 分享一些PPT模板
链接:https://pan.baidu.com/s/1ADlYzx7sWR2z0ltVt8kIAQ 提取码:tyzv
- spring整合shiro框架
上一篇文章已经对shiro框架做了一定的介绍,这篇文章讲述使用spring整合shiro框架,实现用户认证已经权限控制 1.搭建环境 这里不在赘述spring环境的搭建,可以简单的搭建一个ssm框架, ...
- CF919D Substring (dag dp)
传送门 解题思路 感觉这种题都是套路,首先缩点判了环(没看见自环挂了一次..),然后设\(f[x][i]\)表示到了\(x\),\(i\)这个字母走过的最长距离,然后拓扑排序更新即可. 代码 #inc ...
- BZOJ 1087(SCOI 2005) 互不侵犯
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 5333 Solved: 3101 [Submit][ ...
- hibernate_04_hibernate多对多的关系映射
1.实体类的多对多的关系映射 一个用户可以有多个角色 User.java public class User { private Long user_id; private String user_c ...
- Flink常用资料网址
Flink官网https://flink.apache.org/ 阿里flink开发文档 https://help.aliyun.com/product/45029.html?spm=a2c4g.11 ...