【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, 一个是静态大小, 一个是增加多了会对 ...
随机推荐
- redux有价值的文档
使用 Redux 管理状态,第 1 部分 https://www.ibm.com/developerworks/cn/web/wa-manage-state-with-redux-p1-david-g ...
- AlexNet梳理
创新点 成功的使用relu函数替代了sigmoid函数,解决了使用sigmoid的梯度消散问题 成功的在全连接层使用dropout 成功的使用重叠最大池化 提出了LRN 利用GPU进行运算 数据增强2 ...
- 2.Servlet入门
一.Servlet简介 Servlet为sun公司开发动态web的一门技术 Sun公司在这些API中提供了一个接口叫做:Servlet,如果想开发Servlet程序,需要完成两个小步骤: 编写一个类, ...
- P3386 【模板】二分图匹配(匈牙利算法)
题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 ...
- LSTM的神经元个数
小书匠深度学习 目录: 1.LSTM简单介绍 2.简单假设样例 3.神经元分析 3.1忘记门层 3.2细胞状态 3.3输出层 3.4总结 4.测试 1.LSTM简单介绍 LSTM在时间上展开 红框从左 ...
- Java Array二维数组使用
二维数组:元素为一维数组的数组 package myArray.arrayarray; /* *二维数组:元素为一维数组的数组 * * 定义格式: * A:数组类型[][] 数组名: (推荐用法) * ...
- bzoj 3585 mex - 线段树 - 分块 - 莫队算法
Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问 ...
- Apache Kylin - 大数据下的OLAP解决方案
OLAPCube是一种典型的多维数据分析技术,Cube本身可以认为是不同维度数据组成的dataset,一个OLAP Cube 可以拥有多个维度(Dimension),以及多个事实(Factor Mea ...
- fastjson在反序列化时,解析对象中的继承,抽象类处理
LimitActionConfig是ActionConfig的子类,RuleConfig的有个属性是ActionConfig,需要反序列化成LimitActionConfig ParserConfig ...
- NioEventLoopGroup源码分析与线程设定
我的以Netty Socket编程的代码为例, 1.EventLoopGroup 进入EventLoopGroup,这是一个特殊的EventExecutorGroup,在事件循环中,在selectio ...