【Codeforces627E】Orchestra(双指针_链表)
题目
翻译
好久没做英语阅读了,来爽一爽吧 ~
描述
保罗是管弦乐队的成员。弦乐组安排在一个 \(r\times c\) 的矩形方格区域中,其中有 \(n\) 个中提琴手 (violist) ,其余都是小提琴手 (violinist) 。保罗很喜欢中提琴 (viola) ,因此他想拍一张至少包含 \(k\) 个中提琴的照片。保罗可以为管弦乐队中任意一个与坐标轴平行的矩形区域拍照。求出保罗可以拍出的照片的数量。
两张照片不同当且仅当对应的矩形的坐标不同。
输入
第一行输入四个空格隔开的整数 \(r,c,n,k(1\leq r,c,n \leq 3000,1\leq k\leq \min(n,10)\) —— 依次为弦乐组的长和宽,中提琴手的总数和保罗希望照片里中提琴的最少数量。
接下来 \(n\) 行,每行两个整数 \(x_i\) 和 \(y_i(1\leq x_i\leq r,1\leq y_i\leq c)\) :第 \(i\) 个中提琴的位置。保证输入中每个位置出现最多一次。
输出
输出一个整数 —— 保罗可以拍出的至少包含 \(k\) 个中提琴的照片的数量。
分析
为什么他们都会这道题就我不会啊。难受。
以下方便起见设矩阵为 \(n\times m\) ,中提琴数量为 \(V\) …… 懒得改了
有一个很显然的 \(O(n^2m)\) 的暴力:枚举选取的矩阵的上界和下界 \([t,b](1\leq t\leq b\leq n)\),然后用双指针(又称尺取法)算出此时 \([1,m]\) 中有多少个区间 \([l,r](1\leq l\leq r\leq m)\) 满足以 \((t,l)\) 为左上角、 \((b,r)\) 为右下角的矩形(下称 \([l,r]\) 的「对应矩形」)中有至少 \(k\) 个中提琴。
注意到中提琴最多只有 \(3000\) 个,考虑不枚举每一列,而只枚举中提琴,这样总复杂度(没准)能变成 \(O(n^2+nV)\) 之类的东西 …… ?
如果现在处理的行区间是 \([t,b]\) ,当 \(b\) 变成 \(b-1\) 时,由「合法」(即对应矩形中至少有 \(k\) 个中提琴)变为「不合法」的区间 \([l,r]\) ,一定在 \(b\) 这一行包含了至少一个中提琴。因此,只需要枚举 \(b\) 行的中提琴,然后看它让多少个 \([l,r]\) 不合法了即可。更进一步,枚举这一行中的中提琴,找有多少个区间 \([l,r]\) 包含它且对应矩形的中提琴数 恰好 为 \(k\) ,然后删掉这个中提琴。这样就可以不重不漏地统计到所有由合法变为不合法的区间。
还能注意到 \(k\) 非常小。这说明满足条件的 \(l\) 和当前枚举到的中提琴之间不会超过 \(k\) 个「有效列」(指在 \([t,b]\) 中至少一行存在中提琴的列),对于 \(r\) 亦是如此。那么只需要枚举 \(l\) ,用双指针统计即可。「有效列」可以用链表维护。这样就可以在 \(O(k)\) 时间内统计出有多少个包含某个点的区间对应矩形包含的中提琴数恰好为 \(k\) 。总事件复杂度 \(O(n^2+nm+nVk)\) 。
一些计数的细节详见代码。
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
namespace zyt
{
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3e3 + 10;
int L[N], R[N], s[N], n, m, t, k, num[N];
ll ans;
pii arr[N];
vector<int> g[N];
int work()
{
scanf("%d%d%d%d", &n, &m, &t, &k);
for (int i = 0; i < t; i++)
scanf("%d%d", &arr[i].first, &arr[i].second), g[arr[i].first].push_back(arr[i].second);
for (int i = 1; i <= n; i++)
sort(g[i].begin(), g[i].end());
for (int i = 1; i <= n; i++)
{
memset(num, 0, sizeof(int[m + 1]));
for (int j = i; j <= n; j++)
for (vector<int>::iterator it = g[j].begin(); it != g[j].end(); it++)
++num[*it];
int last = 0;
for (int j = 1; j <= m; j++)
if (num[j])
L[j] = last, R[last] = j, last = j;
R[last] = m + 1;
int now = 0;
for (int l = R[0], r = R[0], tmp = 0; r <= m; r = R[r])
{
tmp += num[r];
while (tmp - num[l] >= k)
tmp -= num[l], l = R[l];
if (tmp >= k)
now += (R[r] - r) * l;
}
for (int j = n; j >= i; j--)
{
ans += now;
for (vector<int>::iterator it = g[j].begin(); it != g[j].end(); it++)
{
int l = *it, r = *it, tmp = 0;
while (L[l] && tmp < k)
tmp += num[l = L[l]];
while (r <= m)
{
tmp += num[r];
while (tmp > k)
tmp -= num[l], l = R[l];
if (l > *it)
break;
if (tmp == k)
now -= (R[r] - r) * (l - L[l]);
r = R[r];
}
if (!(--num[*it]))
R[L[*it]] = R[*it], L[R[*it]] = L[*it];
}
}
}
printf("%lld", ans);
return 0;
}
}
int main()
{
return zyt::work();
}
【Codeforces627E】Orchestra(双指针_链表)的更多相关文章
- BZOJ_1713_[Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会_斜率优化
BZOJ_1713_[Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会_斜率优化 Description Input 第1行输入 ...
- 【Warrior刷题笔记】143.重排链表 【线性化 || 双指针+翻转链表+链表合并】详细注释
题目一 力扣143.重排链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reorder-list/ 1.描述 给定一个单链表L的头节点he ...
- 《LeetBook》leetcode题解(19):Remove Nth Node From End of List[E]——双指针解决链表倒数问题
我现在在做一个叫<leetbook>的开源书项目,把解题思路都同步更新到github上了,需要的同学可以去看看 这个是书的地址: https://hk029.gitbooks.io/lee ...
- (转)c语言_链表实例讲解(两个经典例子)
建立一个学生成绩的线性链表,对其实现插入,删除,输出,最后销毁. #include <stdio.h>#include <stdlib.h> struct grade { ...
- C_数据结构_链表的链式实现
传统的链表不能实现数据和链表的分离,一旦数据改变则链表就不能用了,就要重新开发. 如上说示:外层是Teacher,里面小的是node. #ifndef _MYLINKLIST_H_ #define _ ...
- c语言_链表实例讲解(两个经典例子)
建立一个学生成绩的线性链表,对其实现插入,删除,输出,最后销毁. demo1 // lianbiao.cpp : Defines the entry point for the console app ...
- 指针与数据结构算法_链表(C语言)
一.变量: 声明一个变量系统是没有给这个变量分配内存空间的: 例: int j;//编译的时候是没有分配内存空间的 ;//计算机在编译的时候就会给这个i分配4个字节的内存空间 二.malloc动态分配 ...
- c_数据结构_链表
#include<stdio.h> #include<stdlib.h> #define ERROR 0 #define OK 1 #define OVERFLOW -2 ty ...
- [数据结构]_[C/C++]_[链表的最佳创建方式]
场景 1.链表在C/C++里使用非常频繁, 因为它非常使用, 可作为天然的可变数组. push到末尾时对前面的链表项不影响. 反观C数组和std::vector, 一个是静态大小, 一个是增加多了会对 ...
随机推荐
- Java Array、List、Set互相转化
https://blog.csdn.net/u014532901/article/details/78820124
- Laravel 解决blade模板转义html标签问题
当我们使用富文本编译器(如:Ueditor编译器)保存编辑的内容后,在blade模板中,想要显示原生的html标签内容时该怎么做? 首先,了解下laravel {{ 变量名 }} 与{!! 变量名 ! ...
- vector的使用注意事项
示例1: #include "iostream" #include "vector" using namespace std; int main(void) { ...
- 启动hadoop报does not contain a valid host:port authority:node2_1:9000
报错:启动hadoop报does not contain a valid host:port authority:node2_1:9000 原因:主机的hostname不合法,修改为不包含着‘.’ ' ...
- Linux 查看文件权限命令ls -l 输出信息每列所代表的含义
- 第01组 Alpha冲刺(3/6)
队名:007 组长博客: https://www.cnblogs.com/Linrrui/p/11873424.html 作业博客: https://edu.cnblogs.com/campus/fz ...
- Fluent导出残差总结
在使用Fluent进行求解的时候,有时候我们需要将求解的残差提取出来,进行后续的处理,我们可以采用下面的方法将Fluent求解残差输出.下面我们用一个简单的二维算例来说明(算例来源于:https:// ...
- 如何理解 Web API
什么是web API? web API 控制器.路由 测试 Web API 什么是web API ? 简单说,API是接口,访问程序的某一个功能或者数据,实现移动端和客户端的程序之间的数据交互: ...
- Linux系统实现虚拟内存有两种方法:交换分区(swap分区)和交换文件
Linux系统实现虚拟内存有两种方法:交换分区(swap分区)和交换文件 交换文件 查看内存:free -m , -m是显示单位为MB,-g单位GB 创建一个文件:touch /root/swapfi ...
- IIS 7中添加匿名访问FTP站点
1. 开启FTP和IIS服务: 2.打开IIS 管理器: 我电脑上是IIS 7.5 ,所以选择第一个并点击打开哦. 如果你想知道自己IIS的版本,打开帮助菜单: 3. 新建FTP站点: 4. 填写站点 ...