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

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

比如给你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. static,final关键字,Object类的tostring方法,equals方法,hashCode方法

    1)static关键字 static可以修饰:属性.方法.代码块 静态方法不能访问非静态 属性 或 方法 属性(变量): 成员变量: 静态变量: 通过 类名.静态变量来访问 通过 对象名.静态变量来访 ...

  2. js--判断当前环境是否为app环境

    /** *判断是否是app环境 */ function getIsApp () { var ua = navigator.userAgent.toLowerCase(); if (ua.match(/ ...

  3. 2019/11/1 CSP模拟

    写在前面的反思 该拿的部分分还是得拿完啊,因为懒+动作慢没有写最后一道题的菊花图和链的情况,其实这两个点并不难.. 虽然只有\(10pts\),但是已经足够往上爬一截了啊,额外的\(10pts\)在今 ...

  4. Java-Maven-pom.xml-project-dependencies:dependencies

    ylbtech-Java-Maven-pom.xml-project-dependencies:dependencies 1.java 调用ddl <!-- java 调用ddl --> ...

  5. 阿里云CentOs7上安装GitLab

    一.安装 基本上可以根据官网的教程来安装:https://www.gitlab.com.cn/installation/#centos-7 只不过我们暂时没有邮件服务器,所以postfix没有安装. ...

  6. STM32F4X 关于MDK上虚拟串口调试

    1. 下载安装VSPD 自行百度安装后,利用VSPD将PC上的两个虚拟串口连接起来.如图我将COM1 和COM2连接起来. a. 点击Addr pair. 可以看到Virtual ports上将两个虚 ...

  7. Python - 作为浅拷贝的list对象乘法

    运行下面这段代码 # !/usr/bin/env python3 # -*- coding=utf-8 -*- temp_a = [[0]*2]*3 temp_b = [[0]*2 for i in ...

  8. java_IO流(输入流)

    * 字节输入流(InputStream):所有字节输入流的父类 * 所有子类共性方法: * int read():从输入流中读取数据的下一个字节 * int read(byte[] b):从输入流中拂 ...

  9. C++ Builder获取系统文件的路径

    取得路径的程序:(注意红色字体,由于博客显示问题,所以中间加了空格,大家自己把空格去掉即可) // -------------------------------------------------- ...

  10. 报javax.servlet.ServletException: Servlet.init() for servlet [springmvc] threw exception的解决记录

    1.异常详情: 2.异常分析: 从异常的详情中看出:companyService未找到,出现这种情况的愿意可能是companyServiceImpl类没有交给IOC容器管理,但是经过我已经在该类上打了 ...