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

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

比如给你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. 本地git安装完成之后,从远程git服务器上面下载代码。报错SSL certificate problem:self signed certificate in certificate chain。

    解决方案:打开git的控制端黑窗口,输入: git config --global http.sslVerify false 点击Entry之后,就会去掉git的ssl验证. 然后就可以正常的下载代码 ...

  2. CSIC_716_20191126【面向对象编程--继承】

    继承 什么是继承:继承是新建类的一种方式,通过此方式生成的类称为子类.或者 派生类,被继承的类称为父类.基类或超类.在python中,一个子类可以继承多个父类. 继承的作用:减少代码的冗余,提高开发效 ...

  3. Scala 方法与函数简单记录

    /** * Scala 方法与函数 * Scala 有方法与函数,二者在语义上的区别很小.Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量.换句话来说在类中定义的函数即是方法 */ o ...

  4. thingkphp 路由实例

    我们已经了解了如何定义路由规则,下面我们来举个例子加深印象. 假设我们定义了News控制器如下(代码实现仅供参考): namespace Home\Controller; use Think\Cont ...

  5. BCB编写DLL终极手册

    一. 编写 DLL File/New/Dll 生成 Dll 的向导,然后能够添加导出函数和导出类 导出函数:extern "C" __declspec(dllexport) Exp ...

  6. C#获取当前运行的源代码的文件名和当前源代码的行数的方法

    在C#中记录日志时,为了以后查找错误或者跟踪的方便,最好能记录下出错的源代码的文件名和出错的源代码的行数. 这2个方法如下: /// <summary>         /// 取得当前源 ...

  7. vue.js+element ui Table+spring boot增删改查

    小白初学,不懂的还是太多了,找了好多资料才做出来的先记录一下 1.先用Spring boot创建一个包含了增删改查的项目 2.创建vue.js项目 3.安装Element UI (1)进入项目文件夹下 ...

  8. UVA-699-The Falling Leaves-二叉树+递归

    Each year, fall in the North Central region is accompanied by the brilliant colors of the leaves on ...

  9. day 64 Django基础十之Form和ModelForm组件

    Django基础十之Form和ModelForm组件   本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Mod ...

  10. Spring - 整合MyBatis

    目的: 使用 Spring 容器用单例模式管理 MyBatis 的 sqlSessionFactory : 使用 Spring 管理连接池.数据源等: 将 Dao / Mapper 动态代理对象注入到 ...