CF1167E. Range Deleting
题意
给定长度为\(n\)的数组\(a\),其中任意\(a_i \leq x\)
定义\(f(l,r)\)为删除\(a\)中值域在\([l,r]\)的数后剩余的数组.
统计满足\(1\leq l \leq r \leq x\)且\(f(l,r)\)是非严格不下降序列的数对\((l,r)\)的数量。
题解
首先想想就可以发现这个\(l\)和\(r\)是有单调性的。那思路就可以往双指针/二分那边靠一下。
现在的问题就是怎么做到\(O(1)\)或者\(O(\log n)\) 判断删除一段区间后的序列是否合法。
把最后的序列拆成两段:权值在\((1,l-1)\)和权值在\((r+1,x)\)的。
发现只需要\((1,l-1)\)这段满足按权值排序后下标单调上升,\((r+1,x)\)这段同理,并且\(l-1\)的下标比\(r+1\)的下标小。
那么这个东西其实是可以预处理出来的。
考虑处理出\(posmax\)和\(posmin\)表示数字\(i\)出现的最小下标和最大下标,\(premax\)和\(sufmin\)表示按权值排序后\(1-i\)的最大下标 和 按权值排序后\(i-x\)的最小下标。
依靠上面预处理出来的数据我们就可以再处理出一个\(precan\)和\(sufcan\)表示\((1,i)\)是否合法以及\((i,x)\)是否合法,那么就可以\(O(1)\)判断删除一段区间后的序列是否合法了。
使用双指针就可以做到\(O(n)\)解决。
#include <bits/stdc++.h>
using namespace std;
namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf;
inline char gc() {
if(p1 != p2) return *p1++;
p1 = buf;
p2 = p1 + fread(buf, 1, 1 << 21, stdin);
return p1 == p2 ? EOF : *p1++;
}
#define G gc
#ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif
template<class I>
inline void read(I &x) {
x = 0; I f = 1; char c = G();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
x *= f;
}
template<class I>
inline void write(I x) {
if(x == 0) {putchar('0'); return;}
I tmp = x > 0 ? x : -x;
if(x < 0) putchar('-');
int cnt = 0;
while(tmp > 0) {
buf[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while(cnt > 0) putchar(buf[--cnt]);
}
#define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ')
} using namespace io;
#define ll long long
const int N = 1000100;
const int inf = 1e9;
int n, x;
int a[N];
int posmn[N], posmx[N];
//每个大小的数的最左端点和最右端点
int sufmn[N], premx[N];
//从大到小/从小到大的max和min位置
bool sufcan[N], precan[N];
//保留i到x这段是否合法,保留1到i这段是否合法
bool check(int l, int r) {
if(!precan[l - 1]) return false;
if(!sufcan[r + 1]) return false;
if(sufmn[r + 1] < premx[l - 1]) return false;
return true;
}
int main() {
read(n); read(x);
memset(posmn, 0x3f, sizeof(posmn));
for(int i = 1; i <= n; ++i) read(a[i]);
for(int i = 1; i <= n; ++i) {
posmn[a[i]] = min(posmn[a[i]], i);
posmx[a[i]] = max(posmx[a[i]], i);
}
sufmn[x + 1] = inf;
for(int i = 1; i <= x; ++i) premx[i] = max(premx[i - 1], posmx[i]);
for(int i = x; i; --i) sufmn[i] = min(sufmn[i + 1], posmn[i]);
sufcan[x + 1] = precan[0] = true;
for(int i = 1; i <= x; ++i) precan[i] = precan[i - 1] && (premx[i - 1] < posmn[i]);
for(int i = x; i; --i) sufcan[i] = sufcan[i + 1] && (posmx[i] < sufmn[i + 1]);
ll sum = 0;
int l = 1, r = 1;
for(; l <= x; ++l) {
if(l > r) ++r;
while(r < x && !check(l, r)) ++r;
if(check(l, r)) sum += x - r + 1;
}
outn(sum);
return 0;
}
CF1167E. Range Deleting的更多相关文章
- Codeforces 1167 E Range Deleting 双指针+思维
题意 给一个数列\(a\),定义\(f(l,r)\)为删除\(a\)中所有满足\(l<=a_i<=r\)的数后的数列,问有多少对\((l,r)\),使\(f(l,r)\)是一个 ...
- Educational Codeforces Round 65 (Rated for Div. 2) E. Range Deleting(思维+coding)
传送门 参考资料: [1]:https://blog.csdn.net/weixin_43262291/article/details/90271693 题意: 给你一个包含 n 个数的序列 a,并且 ...
- 1167E - Range Deleting 双指针
题意:给出n个数的序列,并给出x,这n个数的范围为[1,x],f(L,R)表示删除序列中取值为[l,r]的数,问有几对L,R使得操作后的序列为非递减序列 思路:若[l,r]成立,那么[l,r+1],. ...
- Educational Codeforces Round 65 (Rated for Div. 2)题解
Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...
- [ Educational Codeforces Round 65 (Rated for Div. 2)][二分]
https://codeforc.es/contest/1167/problem/E E. Range Deleting time limit per test 2 seconds memory li ...
- codeforces Educational Codeforces Round 65 (补完)
C News Distribution 并查集水题 D Bicolored RBS 括号匹配问题,如果给出的括号序列nesting depth为n,那么最终可以分成两个nesting depth为n ...
- Educational Codeforces Round 65 E,F
E. Range Deleting 题意:给出一个序列,定义一个操作f(x,y)为删除序列中所有在[x,y]区间内的数.问能使剩下的数单调不减的操作f(x,y)的方案数是多少. 解法:不会做,思维跟不 ...
- Educational Codeforces Round 65 选做
好久没更博客了,随便水一篇 E. Range Deleting 题意 给你一个长度为 \(n\) 的序列 \(a_1,a_2,\dots a_n\) ,定义 \(f(l,r)\) 为删除 \(l\le ...
- Codeforces Edu Round 65 A-E
A. Telephone Number 跟之前有一道必胜策略是一样的,\(n - 10\)位之前的数存在\(8\)即可. #include <iostream> #include < ...
随机推荐
- 【视频开发】CximageMat 、CximagelplImage 以及 lplImageMat的转换、像素位深度
1.传统的lplImage * -------> Mat格式 IplImage* img = cvLoadImage("greatwave.png", 1); Mat mtx ...
- vcf和bed的位置信息区别
vcf和bed的位置信息区别 vcf和gff一般是从1-base开始计数,也就是文件里所代表的的位置是染色体的真实位置 bed文件一般所代表的位置是从0开始计数的,是一个半闭合区间,也就是(0,200 ...
- python爬虫scrapy(一)
一,准备scrapy依赖组件环境,按照以下顺序安装 .wheel pip install wheel .lxml http:.PyOpenssl https://pypi.python.org/pyp ...
- hdu 2841 题解
题目 题意:就是问在一个$ n* m $的矩阵中站在 $ (0,0) $ 能看到几个整数点. 很明显如果有两个平行向量 $ \vec{a}=(x_1,y_1) $ ,$ \vec{b}=(x_2,y_ ...
- 彩蛋(Python)-------都是细节
• python所有的符号全部是英文的符号• 数字和bool不支持迭代,列表支持• 列表有序,可变,支持索引• 元组有序,不可变,支持索引• 字典是无序的,可变的数据类型,不支持索引.• 集合,无值的 ...
- AVR单片机教程——按键动作
上一篇教程中我们学习了如何读取按键状态.而按键的动作,比如单击,至少需要两个状态才能判定,长按.双击的判定更加复杂.今天我们来学习如何使用库函数判断按键单击,以及其实现原理. 我们要实现的是:当一个按 ...
- c# 基于委托的异步编程模型(APM)测试用例
很多时候,我们需要程序在执行某个操作完成时,我们能够知道,以便进行下一步操作. 但是在使用原生线程或者线程池进行异步编程,没有一个内建的机制让你知道操作什么时候完成,为了克服这些限制,基于委托的异步编 ...
- Python之TensorFlow的基本介绍-1
一.TensorFlow™是一个基于数据流编程(dataflow programming)的符号数学系统,被广泛应用于各类机器学习(machine learning)算法的编程实现,其前身是谷歌的神经 ...
- c# 异步( Async ) 不是多线程
c# 异步( Async ) 不是多线程 误解 async 在调试 xxxxAsync() 方法的时候,常常会看到调试器界面中会多出一些线程,直觉上误认为 Async 冠名的函数是多线程. 对于 ...
- ES6之promise原理
我在这里介绍了promise的原理: https://juejin.im/post/5cc54877f265da03b8585902 我在这里 仅仅张贴 我自己实现的简易promise——DiProm ...