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

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

比如给你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把分数表示成最简形式

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <map>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 #include <time.h>
 10
 11 #define SIGMA_SIZE 26
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define goe(i, a, b) for(int i=a; i<=b; i++)
 16 #define go(i, a, b) for(int i = a; i < b; i++);
 17 #pragma warning ( disable : 4996 )
 18
 19 using namespace std;
 20 typedef long long LL;
 21 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
 22 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
 23 inline LL lgcd( LL a, LL b ) { return b==0?a:lgcd(b,a%b); }
 24 inline LL llcm( LL a, LL b ) { return a/lgcd(a,b)*b; }  //a*b = gcd*lcm
 25 inline int Max(int a,int b)    { return a>b?a:b; }
 26 inline int Min(int a,int b)       { return a>b?b:a; }
 27 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
 28 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
 29 const LL INF = 0x3f3f3f3f3f3f3f3f;
 30 const LL mod  = 1000000007;
 31 const double eps = 1e-8;
 32 const int inf  = 0x3f3f3f3f;
 33 const int maxk = 5e4+5;
 34 const int maxn = 3e4+5;
 35
 36 int belong[maxk], wazi[maxk];
 37 int N, M, unit;
 38 LL ans, cnt[maxk], fina[maxk], finb[maxk];
 39 struct query {
 40     int lhs, rhs, id;
 41     LL a, b;    //分子和分母
 42 }q[maxk];
 43
 44 bool cmp(const query& a, const query& b)
 45 {
 46     if (belong[a.lhs] == belong[b.lhs]) return a.rhs < b.rhs;
 47     return a.lhs < b.lhs;
 48 }
 49
 50 void revise( int x, int d )
 51 {
 52     //ans先减去以前的贡献再加上现在的贡献
 53     ans -= cnt[wazi[x]]*cnt[wazi[x]];
 54     cnt[wazi[x]] += d;
 55     ans += cnt[wazi[x]]*cnt[wazi[x]];
 56 }
 57
 58 void read()
 59 {
 60     scanf("%d %d", &N, &M); unit = sqrt(N);
 61
 62
 63     goe(i, 1, N) { scanf("%d", &wazi[i]); belong[i] = i/unit+1; }
 64     goe(i, 1, M) { scanf("%d %d", &q[i].lhs, &q[i].rhs); q[i].id = i; }
 65     sort(q+1, q+1+M, cmp);
 66
 67 }
 68
 69
 70 int main()
 71 {
 72     read();
 73
 74     int l = 1, r = 0;
 75     ans = 0;
 76
 77     goe(i, 1, M)
 78     {
 79         //如果是减操作,则先要执行revise,
 80         //注意顺序
 81         while(l < q[i].lhs) { revise(l, -1); l++; }
 82         while(l > q[i].lhs) { l--; revise(l, 1); }
 83         while(r < q[i].rhs) { r++; revise(r, 1); }
 84         while(r > q[i].rhs) { revise(r, -1); r--; }
 85
 86         if ( q[i].lhs == q[i].rhs ) { q[i].a = 0; q[i].b = 1; continue; }
 87         q[i].a = ans - (q[i].rhs - q[i].lhs + 1);
 88         q[i].b = (LL)1*(q[i].rhs - q[i].lhs)*(q[i].rhs - q[i].lhs + 1);
 89
 90         LL Gcd = lgcd(q[i].a, q[i].b);
 91         q[i].a /= Gcd;
 92         q[i].b /= Gcd;
 93     }
 94
 95     goe(i, 1, M)
 96     {
 97         fina[q[i].id] = q[i].a;
 98         finb[q[i].id] = q[i].b;
 99     }
100
101     goe(i, 1, M)
102         printf("%lld/%lld\n", fina[i], finb[i]);
103
104     return 0;
105 }

View Code

待修改的莫队,这就有点难受了,原先的二维区间变成了三维,加了一个时间维度(怎么感觉怪怪的),大意就是原先每个结构体多存储一个了时间变量,修改操作也通过时间变量储存,并且通过change这一数据结构将一系列修改的数据存储下来(即能通过时间确定修改的值,就像能操纵时间,随时可以通过时间还原原来的序列或者变化成修改后的序列),然后就是在原始莫队的基础上加上一个时间维度的移动,不得不说这个算法真是朴素而美妙...

HYSBZ 2120 数颜色---模板题

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <map>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 #include <time.h>
 10
 11 #define SIGMA_SIZE 26
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fo(i, a, b) for(int i = a; i < b; i++);
 17 #pragma warning ( disable : 4996 )
 18
 19 using namespace std;
 20 typedef long long LL;
 21 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
 22 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
 23 inline LL lgcd( LL a, LL b ) { return b==0?a:lgcd(b,a%b); }
 24 inline LL llcm( LL a, LL b ) { return a/lgcd(a,b)*b; }  //a*b = gcd*lcm
 25 inline int Max(int a,int b)    { return a>b?a:b; }
 26 inline int Min(int a,int b)       { return a>b?b:a; }
 27 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
 28 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
 29 const LL INF = 0x3f3f3f3f3f3f3f3f;
 30 const LL mod  = 1000000007;
 31 const double eps = 1e-8;
 32 const int inf  = 0x3f3f3f3f;
 33 const int maxk = 1e6+5;
 34 const int maxn = 1e4+5;
 35
 36
 37 int belong[maxn], num[maxn], now[maxn], fin[maxn];
 38 int N, Q, unit, l, r;
 39 int t, T, Time, ans;
 40 int cnt[maxk];
 41
 42 struct query {
 43     int lhs, rhs, tim, id;
 44     query() {}
 45     query(int l, int r, int t, int i)
 46         : lhs(l), rhs(r), tim(t), id(i) {}
 47
 48 }q[maxn];
 49
 50 // pos表示修改的位置,new表示修改后的值,Old表示修改前的值
 51 struct change {
 52     int pos, New, Old;
 53     change() {}
 54     change(int p, int n, int o)
 55         : pos(p), New(n), Old(o) {}
 56 }c[maxn];
 57
 58 bool cmp(const query& a, const query& b)
 59 {
 60     if (belong[a.lhs != b.lhs]) return a.lhs < b.lhs;
 61     if (belong[a.rhs != b.rhs]) return a.rhs < b.rhs;
 62     return a.tim < b.tim;
 63 }
 64
 65 void read()
 66 {
 67     //最优分块策略不再是根号
 68     scanf("%d %d", &N, &Q); unit = pow((double)N, (double)0.666666);
 69     foe(i, 1, N) { scanf("%d", &num[i]); now[i] = num[i]; belong[i] = i/unit+1; }
 70
 71     char str[2];
 72     int x, y; t = T = 0;
 73     foe(i, 1, Q)
 74     {
 75         scanf("%s %d %d", str, &x, &y);
 76         if (str[0] == 'Q') q[++t] = query(x, y, T, t);
 77         if (str[0] == 'R') { c[++T] = change(x, y, now[x]); now[x] = y; }
 78     }
 79     sort(q+1, q+t+1, cmp);
 80 }
 81
 82 void revise(int x, int d)
 83 {
 84     cnt[x] += d;
 85     if (d > 0)
 86         ans += (cnt[x] == 1);        //只有从0加到1才会增加一种颜色数量
 87     if (d < 0)
 88         ans -= (cnt[x] == 0);
 89 }
 90
 91 void reviseT(int x, int d)
 92 {
 93     if ( x >= l && x <= r )
 94     {
 95         revise(d, 1);
 96         revise(num[x], -1);
 97     }
 98     num[x] = d;
 99 }
100
101 int main()
102 {
103     read();
104
105     l = 1; r = 0; Time = 0;
106     foe(i, 1, t)
107     {
108         //若修改时间小于tim,则要添加新的修改
109         while(Time < q[i].tim) { Time++; reviseT(c[Time].pos, c[Time].New); }
110         //若time大于tim,则还原老修改
111         while(Time > q[i].tim) { reviseT(c[Time].pos, c[Time].Old); Time--; }
112
113         while(l < q[i].lhs) { revise(num[l], -1); l++; }
114         while(l > q[i].lhs) { l--; revise(num[l], 1); }
115         while(r < q[i].rhs) { r++; revise(num[r], 1); }
116         while(r > q[i].rhs) { revise(num[r], -1); r--; }
117
118         fin[q[i].id] = ans;
119
120     }
121
122     foe(i, 1, t)
123         printf("%d\n", fin[i]);
124
125     return 0;
126 }

View Code

转载于:https://www.cnblogs.com/chaoswr/p/9341987.html

初识莫队——小Z的袜子相关推荐

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

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

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

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

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

    题目传送门 1 /* 2 莫队算法:求出[l, r]上取出两只相同袜子的个数. 3 莫队算法是离线处理一类区间不修改查询类问题的算法.如果你知道了[L,R]的答案,可以在O(1)的时间下得到 4 [L ...

  4. BZOJ2038 小Z的袜子 (莫队算法)

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=2038 专题练习: http://acm.hust.edu.cn/vjudge/conte ...

  5. P1494 [国家集训队]小Z的袜子/莫队学习笔记(误

    P1494 [国家集训队]小Z的袜子 题目描述 作为一个生活散漫的人,小\(Z\)每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小\(Z\)再也无法忍受这恼人的找袜子过程,于是他 ...

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

    莫队也是暴力的一种,不过可以很有效的降低复杂度 如果我们已知[l, r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l, r-1]的答案,即可使用莫队算法. 时间复杂度为O(n^1.5).如 ...

  7. 清橙A1206 小Z的袜子(莫队算法)

    A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB   总提交次数:744   AC次数:210   平均分:44.44 将本题分享到:        查看未格式化的试题    ...

  8. [bzoj 2038 OR 清橙A1206 小Z的袜子]莫队算法

    [bzoj 2038 OR 清橙A1206 小Z的袜子]莫队算法 题意描述:[清橙A1206 时限:1s] [bzoj 2038 时限:20s] 题意描述: 作为一个生活散漫的人,小Z每天早上都要耗费 ...

  9. 【清橙 A1206】小Z的袜子(莫队算法)

    [清橙 A1206]小Z的袜子(莫队算法) A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB   总提交次数:1144   AC次数:319   平均分:43.15 将本题分 ...

最新文章

  1. 剑指Offer_Python实现
  2. 创客编程帮助孩子提升学习成绩,是一项长远投资!
  3. 聊一聊 Redis 数据内部存储使用到的数据结构
  4. 2进程之间的关系:进程组,会话,守护进程
  5. c语言排队系统,【分享】C语言 银行取票排队系统
  6. linux centos目录结构(一)
  7. java se官网_Java下载|Java SE Development Kit官方下载-太平洋下载中心
  8. linux 下载hbase源码,linux上安装hbase(示例代码)
  9. 计算机中文件名无法更改原因,电脑系统文件夹名称修改不了怎么办
  10. 如何完全禁止win10自动更新(自动升级)
  11. Oracle RAC命令
  12. Aidlearning的内网穿透
  13. 关于“知识共享”的几个基本概念
  14. 多线程核心8-3:线程三大安全问题之发布与逸出
  15. MATLAB对ply文件格式的读取和显示
  16. 算法设计与分析复习--回溯法
  17. springBoot+mybatisPlus项目骨架
  18. 给一个向量进行归一化
  19. lvds单8转双8芯片_LVDS驱动芯片
  20. 关闭-您继续使用该词

热门文章

  1. 二进制(bit)整数
  2. Java的不同版本:J2SE、J2EE、J2ME的区别
  3. 链表游戏:CVE-2017-10661之完全利用
  4. 在geth客户端调用已部署的智能合约
  5. java中常用的一些方法(一)
  6. nginx fastcgi python_linux下nginx+python+fastcgi部署总结(django版)
  7. JZOJ 3597. 【CQOI2014】危桥
  8. python locust 能压测数据库_深入浅出 Locust 实现
  9. python内存管理说法错误_python面试题总结1-内存管理机制
  10. 网页按钮跳转位置_RPA工具BizRobo!之运用网页数据处理