以前一直觉得莫队是多么高大上的一种算法,然而仔细看了下发现其实并不复杂,实质上就是技巧性的暴力美学。

在我看来莫队是一种分块排序后降低复杂度的算法,当答案可以通过左右端点一个一个移动维护出来的时候就可以使用莫队了。

比如给你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的袜子的更多相关文章

  1. 莫队-小Z的袜子

    ----普通莫队 首先清楚概率怎么求假设我们要求从区间l到r中拿出一对袜子的概率sum[i]为第i种袜子在l到r中的数量 $$\frac{\sum_{i=l}^{r} {[sum[i] \times ...

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

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

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

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2038 2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 ...

  4. BZOJ-2038 小Z的袜子(hose) 莫队算法

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MB Submit: 5573 Solved: 2568 [Subm ...

  5. BZOJ 2038 [2009国家集训队]小Z的袜子 莫队

    2038: [2009国家集训队]小Z的袜子(hose) 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Descriptionw ...

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

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

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

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

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

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

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

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

随机推荐

  1. Appium 微信 webview 的自动化技术

    Appium 微信 webview 的自动化技术   最近好多人问微信webview自动化的事情, 碰巧我也在追微信webview的自动化和性能分析方法. 先发出来一点我的进展给大家参考下. 此方法用 ...

  2. scala 中List的简单使用

    /** * scala 中List的使用 * */ object ListUse { def main(args: Array[String]): Unit = { def decorator(l:L ...

  3. 软件设计师_朴素模式匹配算法和KMP算法

    1.从主字符串中匹配模式字符串(暴力匹配) 2. KMP算法

  4. 混合云存储组合拳:基于云存储网关与混合云备份的OSS数据备份方案

    前言 阿里云对象存储(OSS)用户众多.很多用户因为业务或者合规性需求,需要对OSS内的数据做备份,无论是线上备份,还是线下备份.用户可以选择使用OSS的开放API,按照业务需求,做数据的备份,也可以 ...

  5. hadoop新增新数据节点和退役数据节点

    新增数据节点 0. 需求随着公司业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点.1. 环境准备 (1)在hadoop03主机上再克 ...

  6. grunt是什么

    Grunt是什么? 博客分类: Grunt GruntJavascript  Grunt是一个自动化的项目构建工具.如果你需要重复的执行像压缩,编译,单元测试,代码检查以及打包发布的任务.那么你可以使 ...

  7. ON_EVENT 报错

    错误提示: error C2440: 'initializing' : cannot convert from 'const wchar_t [1]' to 'UINT' error C2440: ' ...

  8. node环境下安装vue-cli

    一. node安装 1)如果不确定自己是否安装了node,可以在命令行工具内执行: node -v  (检查一下 版本): 2)如果 执行结果显示: xx 不是内部命令,说明你还没有安装node , ...

  9. Spring Boot 发布 jar 包转为 war 包秘籍。

    Spring Boot是支持发布jar包和war的,但它推荐的是使用jar形式发布.使用jar包比较方便,但如果是频繁修改更新的项目,需要打补丁包,那这么大的jar包上传都是问题.所以,jar包不一定 ...

  10. vue项目实现按需加载的3种方式

    vue异步组件技术 vue-router配置路由,使用vue的异步组件技术,可以实现按需加载.这种方式下一个组件生成一个js文件 用例: { path: '/promisedemo', name: ' ...