题意

给定长度为\(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的更多相关文章

  1. Codeforces 1167 E Range Deleting 双指针+思维

    题意 给一个数列\(a​\),定义\(f(l,r)​\)为删除\(a​\)中所有满足\(l<=a_i<=r​\)的数后的数列,问有多少对\((l,r)​\),使\(f(l,r)​\)是一个 ...

  2. Educational Codeforces Round 65 (Rated for Div. 2) E. Range Deleting(思维+coding)

    传送门 参考资料: [1]:https://blog.csdn.net/weixin_43262291/article/details/90271693 题意: 给你一个包含 n 个数的序列 a,并且 ...

  3. 1167E - Range Deleting 双指针

    题意:给出n个数的序列,并给出x,这n个数的范围为[1,x],f(L,R)表示删除序列中取值为[l,r]的数,问有几对L,R使得操作后的序列为非递减序列 思路:若[l,r]成立,那么[l,r+1],. ...

  4. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  5. [ 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 ...

  6. codeforces Educational Codeforces Round 65 (补完)

    C News Distribution 并查集水题 D Bicolored RBS 括号匹配问题,如果给出的括号序列nesting depth为n,那么最终可以分成两个nesting depth为n ...

  7. Educational Codeforces Round 65 E,F

    E. Range Deleting 题意:给出一个序列,定义一个操作f(x,y)为删除序列中所有在[x,y]区间内的数.问能使剩下的数单调不减的操作f(x,y)的方案数是多少. 解法:不会做,思维跟不 ...

  8. Educational Codeforces Round 65 选做

    好久没更博客了,随便水一篇 E. Range Deleting 题意 给你一个长度为 \(n\) 的序列 \(a_1,a_2,\dots a_n\) ,定义 \(f(l,r)\) 为删除 \(l\le ...

  9. Codeforces Edu Round 65 A-E

    A. Telephone Number 跟之前有一道必胜策略是一样的,\(n - 10\)位之前的数存在\(8\)即可. #include <iostream> #include < ...

随机推荐

  1. 算法练习之x的平方根,爬楼梯,删除排序链表中的重复元素, 合并两个有序数组

    1.x的平方根 java (1)直接使用函数 class Solution { public int mySqrt(int x) { int rs = 0; rs = (int)Math.sqrt(x ...

  2. Linux 上安装 appium

    在linux 环境下安装需要以下几步:1.安装node.js, 通过  uname -a  命令查看到我的Linux系统位数是64位(备注:x86_64表示64位系统, i686 i386表示32位系 ...

  3. Burp Suite 如何抓取HTTPS请求

    1,下载安装burp suite工具 https://portswigger.net/burp/communitydownload 如果是windows系统,选择windows点击Download下载 ...

  4. R统计数据框的行数

    如下三种方法可以实现 使用dim函数 dim(dataframe)[0] 使用nrow函数 nrow(dataframe) 使用length函数统计 length(dataframe[,1])

  5. 【LEETCODE】46、999. Available Captures for Rook

    package y2019.Algorithm.array; /** * @ProjectName: cutter-point * @Package: y2019.Algorithm.array * ...

  6. (转)Nginx+rtmp+ffmpeg搭建流媒体服务器

    (1)下载第三方扩展模块nginx-rtmp-module # mkdir module && cd module //创建一个存放模块的目录 # wget https://githu ...

  7. ubuntu配置Selenium+Chromedriver

    1.下载并安装最新的Google Chrome版本执行如下命令: wget https://dl.google.com/linux/direct/google-chrome-stable_curren ...

  8. 创建Core项目使用IdentityServer4

    本文主要参照https://www.bilibili.com/video/av42364337/?p=4 英文帮助文档:https://identityserver4.readthedocs.io/e ...

  9. IIS初始化设置预加载,解决程序池被回收第一次访问慢问题

    问题现象: 部署到IIS上的项目,第一次访问比较慢,有时后空闲一段时间去访问也会很慢,经常隔天访问也会慢.这就是IIS回收导致的问题,IIS回收把程序池的内存释放,网站就相当与重启的状态,被回收后,我 ...

  10. 关于移动端图片浏览,previewimage的使用

    我相信在移动端项目中,大家都会遇到图片浏览的问题,像qq,微信,微博,淘宝,当你点击图片时,图片会放大全屏显示,双击图片时图片继续放大查看,双指左右滑动也可以放大,当你再次点击时图片,图片恢复原始大小 ...