[eJOI2020 Day1] Exam(性质,转化,dp)

发布时间 2023-04-19 09:15:19作者: Crazy!!!

题意

操作:每次可选一段区间覆盖为原区间最大值。
目标:\(A\)\(B\)中相等的位尽量多。

思路

每个值只有为 \(B_i\) 时才会贡献答案,设 \(A_i\) 左边第一个为 \(B_i\) 的为 \(L_i\) ,同理右边的为 \(R_i\),当然还要满足 \((L_i,i]\)\([i,R_i)\) 的值均 \(\le B_i\)
然后就是突破口:\(A_i\)一定由\(L_i\)或者\(R_i\)覆盖过来,因为覆盖区间越少,合法的概率更大,且改动得(后效性)越小。
如果将每个点\(i\)向所选的覆盖到的位置(\(L_i / R_i\))连边,出现交叉显然是不行的,比如 \(i\)\(L_i\) ,那么 \([L_i,i)\) 的点值最终至少是 \(A_{L_i}=B_i\) 了,所以连向的位置 \(\le L_i\)
既然没有交叉,那从前往后匹配就是有序的,DP就好了,每次转移到加入\(i\)个的匹配,只需要更新 \(L_i\)\(R_i\) 处即可。

code

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;

#define lowbit(x) (x & -(x))

int L[N], R[N], a[N], b[N], st[N], tp, c[N], n;
map<int, int> mp;

void Update(int x, int d) {for(; x <= n; x += lowbit(x)) c[x] = max(c[x], d);}
int Mx(int x) {int mx = 0; for(; x; x -= lowbit(x)) mx = max(mx, c[x]); return mx;}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {scanf("%d", &a[i]);}
	for(int i = 1; i <= n; i++) {scanf("%d", &b[i]);}
	for(int i = 1; i <= n; i++) {
		while(tp && a[st[tp]] <= a[i]) {mp[a[st[tp--]]] = 0;}
		st[++tp] = i; mp[a[i]] = i;
		L[i] = mp[b[i]];
	}
	tp = 0; mp.clear();
	for(int i = n; i; i--) {
		while(tp && a[st[tp]] <= a[i]) {mp[a[st[tp--]]] = 0;}
		st[++tp] = i; mp[a[i]] = i;
		R[i] = mp[b[i]];
	}
	for(int i = 1; i <= n; i++) {
		int l = Mx(L[i]), r = Mx(R[i]);
		if(L[i]) Update(L[i], l + 1);
		if(R[i]) Update(R[i], r + 1);
	}
	printf("%d\n", Mx(n));
	return 0;
}