首页 > 其他分享 >题解 P7169 [eJOI2020 Day1] Exam

题解 P7169 [eJOI2020 Day1] Exam

时间:2024-01-13 22:24:16浏览次数:27  
标签:int 题解 pos Day1 P7169 数组 inline

传送门

题意

有两个长度为 \(N\) 的数列 \(A_i\),\(B_i\)。可以对 \(A\) 数组进行若干次操作,每次可以使 \(A_i\) 到 \(A_j\) 中的所有数变成期间的最大值,求最多能使多少个数满足要求。

分析

显然,要使我们的某一个 \(A_x\) 变成 \(B_x\),至少会包含 \(A_{L_x}\) 或 \(A_{R_x}\),\(L_x\) 是 \(x\) 左侧(包括自己)的与 \(B_x\) 相等的第一个的下标,\(R_x\) 是 \(x\) 右侧(包括自己)的与 \(B_x\) 相等的第一个的下标。

但是这还有一个条件,那就是 \(L_x\sim i\) 之间没有大于 \(B_x\) 的数字,\(R_x\) 相似。

解决了 \(L_x\) 与 \(R_x\) 的计算,我们借用这两个数组来解决我们的答案。

形象化的,我们将某一组操作变成一条线段。由上方点 \(i\) 连向下方 \(L_i\) 或 \(R_i\) 的一条边。

并且线与线之间不能相交。

由此,我们可以定义一个数组,\(f_{i,j}\) 表示上方到达 \(i\) 点,下方到达 \(j\) 点的最多条数。

可以得到转移式:\(f_{i,j}= {\textstyle \max_{k=1}^{k\le j} f_{i-1,k}} +1\)。

我们可以利用树状数组来解决。

Code。

#include <bits/stdc++.h>
#include <vector>
//#define int long long
using namespace std;
const int N = 2e5+5;
inline int read() {
	int x;
	scanf("%d",&x);
	return x;
}
int n, m,a[N],b[N],num[N],L[N],R[N],st[N][20],lg[N];
inline void lsh() {
	int cnt=0;
	for(int i=1; i<=n; ++i) num[++cnt]=a[i];
	for(int i=1; i<=n; ++i) num[++cnt]=b[i];
	sort(num+1,num+cnt+1);
	cnt=unique(num+1,num+cnt+1)-num-1;
	for(int i=1; i<=n; ++i) a[i]=lower_bound(num+1,num+cnt+1,a[i])-num;
	for(int i=1; i<=n; ++i) b[i]=lower_bound(num+1,num+cnt+1,b[i])-num;
}

vector<int > pos[N];
struct Bit {
	int c[N+2];
	inline int lowbit(int x) {
		return x&-x;
	}

	inline void change(int x,int y) {
		for(int i=x; i<=N; i+=lowbit(i)) c[i]=max(c[i],y);
	}

	inline int query(int x) {
		int tot=0;
		for(int i=x; i; i-=lowbit(i)) tot=max(tot,c[i]);
		return tot;
	}
} bit;

inline int query(int l,int r) {
	return max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]);
}

signed main() {
	n=read();
	for(int i=1; i<=n; ++i) a[i]=read();
	for(int i=1; i<=n; ++i) b[i]=read();
	lsh();
	for(int i=1; i<=n; ++i) st[i][0]=a[i];
	for(int i=2; i<N; ++i) lg[i]=lg[i/2]+1;
	for(int i=1; i<20; ++i) for(int j=1; j+(1<<i)-1<=n; ++j) st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);
	for(int i=1; i<=n; ++i) pos[a[i]].push_back(i);
	for(int i=1; i<=n; ++i) {
		if(b[i]<a[i]) continue;
		L[i]=upper_bound(pos[b[i]].begin(),pos[b[i]].end(),i)-pos[b[i]].begin()-1;
		if(L[i]>=0) L[i]=pos[b[i]][L[i]];
		else L[i]=0;
		if(L[i]&&query(L[i],i)>b[i]) L[i]=0;
		R[i]=lower_bound(pos[b[i]].begin(),pos[b[i]].end(),i)-pos[b[i]].begin();
		if(R[i]<pos[b[i]].size()) R[i]=pos[b[i]][R[i]];
		else R[i]=0;
		if(R[i]&&query(i,R[i])>b[i]) R[i]=0;
	}
	for(int i=1; i<=n; ++i) {
		int l=bit.query(L[i]),r=bit.query(R[i]);
		if(R[i]) bit.change(R[i],r+1);
		if(L[i]) bit.change(L[i],l+1);
	}
	cout<<bit.query(n);
	return 0;
}

标签:int,题解,pos,Day1,P7169,数组,inline
From: https://www.cnblogs.com/djh0314/p/17963103

相关文章

  • 代码随想录 day18 找树左下角的值 路径总和 从中序与后序遍历序列构造二叉树
    找树左下角的值最简单就是想到层序遍历之后取第一个位置元素就是了递归的话需要先判断哪里最深的节点至于最左保持中左右的遍历顺序第一次得到最大深度处就是最左的路径总和有点像查找子树路径所以递归回溯是比较好的选择在求路径的适合,targetSum-node->val是否为......
  • P5321 [BJOI2019] 送别 题解--zhengjun
    由于大家的做法需要大量分类讨论和代码量,这里提供一种不怎么分类的,容易实现的做法。首先,由于墙体会随时变化,所以直接对墙体本身维护不是很方便。我们可以牺牲一点常数,对\((i,j)\)建立四个点\(UL_{i,j},UR_{i,j},DL_{i,j},DR_{i,j}\)分别表示\((i-\varepsilon,j-\varepsilo......
  • AT_arc125_c [ARC125C] LIS to Original Sequence 题解
    题目传送门前置知识贪心|构造解法对于任意一个未加入序列\(P\)的数\(x<A_{i}(1\lei\lek-1)\),如果其放在了\(A_{i}\)的前面,会导致最长上升子序列长度加一,从而不符合题目要求。因此我们需要把\(x\)放在\(A_{i}\)后面,同理,为符合题目要求,我们仅选择放最小的那一个......
  • Scala编程语言day1
    一、Scala概述Scala是一种运行在JVM上的函数式的面向对象语言,它集成了面向对象编程和面向函数式编程的各种特性,以及更高层的并发模型Scala的语言特点Scala是兼容的:兼容Java,可以访问庞大的Java类库Scala是精简的:Scala表达能力强,开发速度快Scala是高级的:Scala可以让你的程序保......
  • P2198 杀蚂蚁 题解
    题目大意有一条长度为\(n\)个单位长度的路,蚂蚁们要从起点走到终点。蚂蚁们每走\(1\)个单位距离需要\(T\)秒钟。现在,出题人可以在路上修筑\(3\)种防御塔来阻挡蚂蚁的进攻,每个单位距离只能修筑\(1\)座塔,塔的作用分别如下:激光塔:蚂蚁在塔前时每秒会受到\(r\)点伤害。......
  • P3243 [HNOI2015] 菜肴制作 题解
    前言今天考试考到这道题,挂惨了。题意有\(n\)道菜肴,编号为\(1\simn\)。有\(m\)个条件,形如\((i,j)\),表示菜肴\(i\)必须在菜肴\(j\)之前制作。需求出一个菜肴的制作顺序,满足:在满足所有限制的前提下,\(1\)号菜肴尽量优先制作。在满足所有限制,\(1\)号菜肴尽量优......
  • P9007 [入门赛 #9] 最澄澈的空与海 (Hard Version) 题解
    Updon2023.10.1408:21:修改了推式子和题意的一些小错误。前言一道恐怖的绿题。显然我认为应该是蓝题。(不过在这篇题解写到一半的时候升蓝了,感谢@StudyingFather。)名字挺好的。题意给定\(n\),求出满足以下条件的三元组\((x,y,z)\)的组数:\(x\ge0,z\ge1\)。\(......
  • AT_abc243_g [ABC243G] Sqrt题解
    题目大意有一个数列,初始时只有一个数\(X\)。你可以对它进行一种操作:设末尾的数为\(Y\),从\(1\sim\sqrt{Y}\)中选一个数加到数列的末尾。如此进行\(10^{100}\)次操作,问数列一共有多少种可能的状态。解法考虑DP。设\(dp_i\)表示以数字\(i\)开头的数列可能的状态。设......
  • CF713D 题解
    题意给一个\(01\)矩阵,多次求在给定区间内最大的全\(1\)正方形边长。思路容易想到二分:先预处理出以每个位置为右下角的最大合法正方形的边长\(mx_{i,j}\),然后对于每个询问,我们二分边长\(mid\),设当前询问的区间左上角为\((x_1,y_1)\),右下角为\((x_2,y_2)\),则能取到\(mi......
  • AT_arc167_e 题解
    题意给定\(k\)和一个排列\(P'\),问有多少个排列\(P\)以最少步数交换相邻两个元素来进行收敛,最终的排列可能是\(P'\),一个排列是收敛的当且仅当对于每一个数,在该数前且比这个数大的数的个数不超过\(k\)个。思路考虑正向的让一个排列收敛,我们设在第\(i\)个位置前且比\(P......