莫队算法

确实是看过的最良心的讲解: https://www.cnblogs.com/CsOH/p/5904430.html

  • 问题:有n个数组成一个序列,有m个形如询问L, R的询问,每次询问需要回答区间内至少出现2次的数有哪些。

朴素的解法需要读取O(nm)次数。如果数据范围小,可以用数组,时间复杂度为O(nm)。如果使用STL的Map来保存出现的次数,则需要O(nmlogn)的复杂度。有没有更快的方法呢?

注意到询问并没有强制在线,因此我们可以使用离线方法。注意到一点,如果我们有计算完[L, R]时的“中间变量”(在本题为每个数出现的次数),那么[L - 1, R]、[L + 1, R]、[L, R - 1]、[L, R + 1]都能够在“中间变量”的“基本操作时间复杂度”得出。如果能安排适当的询问顺序,使得每次询问都能用上上次运行产生的中间变量,那么我们将可以在更优的复杂度完成整个询问。

如果数据较小,用数组,时间复杂度为O(1);如果数据较大,可以考虑用离散化或map,时间复杂度为O(logn)。

那如何安排询问呢?这里有个时间复杂度非常优秀的方法:首先将每个询问视为一个“点”,两个点P1, P2之间的距离为abs(L1 - L2) + abs(R1 - R2),即曼哈顿距离,然后求这些点的最小生成树,然后沿着树边遍历一次。由于这里的距离是曼哈顿距离,所以这样的生成树被称为“曼哈顿最小生成树”。最小曼哈顿生成树有专用的算法,求生成树时间复杂度可以仅为O(mlogm)。

其实这里是建边的算法,建边后依然使用传统的Prim或者Kruskal算法来求最小生成树。

不幸的是,曼哈顿最小生成树的写法很复杂,考场上不建议这样做.  
一种直观的办法是按照左端点排序,再按照右端点排序。但是这样的表现不好。特别是面对精心设计的数据,这样方法表现得很差。
  举个例子,有6个询问如下:(1, 100), (2, 2), (3, 99), (4, 4), (5, 102), (6, 7)。
  这个数据已经按照左端点排序了。用上述方法处理时,左端点会移动6次,右端点会移动移动98+97+95+98+95=483次。右端点大幅度地来回移动,严重影响了时间复杂度——排序的复杂度是O(mlogm),所有左端点移动次数仅为为O(n),但右端点每个询问移动O(n),共有m个询问,故总移动次数为O(nm),移动总数为O(mlogm + nm)。运行时间上界并没有减少。
  其实我们稍微改变一下询问处理的顺序就能做得更好:(2, 2), (4, 4), (6, 7), (5, 102), (3, 99), (1, 100)。
  左端点移动次数为2+2+1+2+2=9次,比原来稍多。右端点移动次数为2+3+95+3+1=104,右端点的移动次数大大降低了。
  上面的过程启发我们:①我们不应该严格按照升序排序,而是根据需要灵活一点的排序方法;②如果适当减少右端点移动次数,即使稍微增多一点左端点移动次数,在总的复杂度上看,也是划算的。
  在排序时,我们并不是按照左右端点严格升序排序询问,而只是令其左右端点处于“大概是升序”的状态。具体的方法是,把所有的区间划分为不同的块,将每个询问按照左端点的所在块序号排序,左端点块一样则按照右端点排序。注意这个与上一个版本的不同之处在于“第一关键字”是左端点所在块而非左端点。
  莫队算法首先将整个序列分成√n个块(同样,只是概念上分的块,实际上我们并不需要严格存储块),接着将每个询问按照块序号排序(一样则按照右端点排序)。之后,我们从排序后第一个询问开始,逐个计算答案。

模板题:Harvest of Apples

纪念再一次打铁和第一次倒数第一

题目描述

There are n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most m apples.

输入

The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤105).

输出

For each test case, print an integer representing the number of ways modulo 109+7.

样例输入

2
5 2
1000 500

样例输出

16
924129523

组合数的前缀和
将询问离线下来
根据公式递推S(m,n)=2*S(m-1,n)-C(m-1,n-1)来add或erase

#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <set>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <vector>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mp make_pair
#define met(a,x) memset(a,x,sizeof(a))
using namespace std;
const int maxn=1e5+7;
ll ans[maxn],two;
int block;
ll fac[maxn],inv[maxn];
const int mod=1e9+7;
struct node{int l,r,i;bool operator<(const node&c) const {if(l/block==c.l/block){return r/block<c.r/block;}else return l/block<c.l/block;}
}s[maxn];
ll qpow(ll a,ll n){ll res=1;while (n){if(n&1)res=res*a%mod;a=a*a%mod;n>>=1;}return res;
}
void init(){fac[0]=1;for (ll i = 1; i < maxn; ++i) {fac[i]=fac[i-1]*i%mod;}inv[maxn-1]=qpow(fac[maxn-1],mod-2);for (ll i = maxn-2; i>=0 ; --i) {inv[i]=inv[i+1]*(i+1)%mod;}two=qpow(2,mod-2);
}
ll C(int m, int n){if(!m||!n) return 1;if(m<n) return 0;return fac[m]*inv[n]%mod*inv[m-n]%mod;
}
int main(){init();int t;scanf("%d",&t);for (int i = 1; i <=t ; ++i) {scanf("%d%d",&s[i].l,&s[i].r);s[i].i=i;}block=sqrt(1e5);sort(s+1,s+1+t);ll sum=1;for (int i = 1,l=1,r=0; i <=t ; ++i) {while (l<s[i].l){sum=(2*sum%mod-C(l++,r)+mod)%mod;}while (l>s[i].l){sum=(sum+C(--l,r))%mod*two%mod;}while (r<s[i].r){sum=(sum+C(l,++r))%mod;}while (r>s[i].r){sum=(sum-C(l,r--)+mod)%mod;}ans[s[i].i]=sum;}for (int i = 1; i <=t; ++i) {printf("%lld\n",ans[i]);}return 0;
}

转载于:https://www.cnblogs.com/smallocean/p/9695234.html

【学习笔记】莫队算法相关推荐

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

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

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

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

  3. 莫队算法学习笔记(二)——带修莫队

    前言:什么是莫队 莫队算法,是一个十分优雅的暴力. 普通的莫队可以轻松解决一些离线问题,但是,当遇上了一些有修改操作的问题,普通莫队就无能为力了. 于是,改进后的莫队--带修莫队就这样产生了. L i ...

  4. 【算法竞赛学习笔记】莫队算法-超优雅的暴力算法

    title : 莫队算法 tags : ACM,暴力 date : 2021-10-30 author : Linno 普通莫队 常用操作:分块/排序/卡常/离散化等,直接上板子. luoguP270 ...

  5. 【笔记篇】莫队算法(一)

    P.S.:这个星期写了一个星期的莫队,现在也差不多理解了,下周该学点别的了(其实是被long long卡得生活不能自理......快要写吐了). 在本文开始之前,先orz莫涛-- 莫队算法(Mo's ...

  6. C++ 莫队算法(转)

    胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队 在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中,我使 ...

  7. cf D. Powerful array 莫队算法

    D. Powerful array 题意:给定一个序列>>每次查询一个区间>>查询该区间内 出现过的数字*出现的次数的平方 的和 思路:学习莫队的第一题或者说小z的袜子是第一题 ...

  8. 莫队算法 ( MO's algorithm )

    莫队算法是由清华大学神牛莫涛发明的一种处理区间问题的离线算法 算法核心是通过先将问询区间总长度平方分块.然后将所有的问询区间按照左端点所在的块编号排序.在同一块内的则按右端点升序 然后设置左右两个下标 ...

  9. 莫队算法二(树上莫队cot2,Haruna’s Breakfast)

    例一:不带修改 Count on a tree II Time Limit: 1207MS   Memory Limit: 1572864KB   64bit IO Format: %lld & ...

最新文章

  1. iOS开发之圆角指定
  2. HDFS namenode 高可用(HA)搭建指南 QJM方式 ——本质是多个namenode选举master,用paxos实现一致性...
  3. SqlServerException:拒绝对表对象的select,insert权限解决(新建账号导致的问题)
  4. 关于C# Winform DataGridView 设置DefaultCellStyle无效的原因与解决方案
  5. Xmemcached学习笔记一(安装memcached)
  6. 利用F#库canopy进行UI测试
  7. JavaScript学习笔记——事件
  8. 旅游捞金的六大方式,玩着把钱赚了
  9. 关于COM的Reg-Free(免注册)技术简介及实例讲解。
  10. 毕业写论文不要傻傻的到中国知网CNKI充值了,分享几个常用的写论文必备的网站!
  11. DDD中的“领域模型”
  12. ImageJ自动测量每个细胞平均荧光强度及批量处理多张图片
  13. Service的绑定过程
  14. 阿里云服务器如何进行快照备份
  15. Linux Ubuntu 虚拟机不能连网、Linux Ubuntu 虚拟机怎么连网
  16. apt-get update和apt-get upgrade的区别
  17. 利用Python3开发一款小工具(环境配置)
  18. 杰理之BQB 的 RF 测试【篇】
  19. matlab取矩阵满足条件,[MATLAB]矩阵中寻找满足条件的元素
  20. pcx游程编码、解码超详细讲解(附带java源码)

热门文章

  1. SUID、SGID、粘滞位
  2. PostgreSQL 分库分表 插件之一 pg_shard
  3. 【万里征程——Windows App开发】数据绑定——简单示例、更改通知、数据转换...
  4. java开发之提高java和mysql代码性能和质量
  5. JS小游戏-极速快跑
  6. 献给初学者,[winform]中如何设计高效全局的快捷键?[ShortcutKeys]
  7. GDB 调试命令讲解-转
  8. 一步一步手绘Spring IOC运行时序图二(基于XML的IOC容器初始化)
  9. python判断是否为素数_python判断是否为素数
  10. SQL Server Log Shipping学习总结