CC April 18 Cutting Plants 单调队列+思维

题意:长度为n的序列A,B.操作:选定一个区间[L,R]将里面的数变为h , h<=min(a[L],a[L+1]...a[R]).
n<=1e5,1<=a[i],b[i]<=1e9. 问将序列A变为序列B最少需要多少次操作? 无解输出-1.

假设某次操作是将[L,R]内的数变为x.
则x要满足   max(b[i]) <= x <= min(a[i])  i=[L...R].

因为最多操作n次. 所以每一次操作[L,R,x] 这个x肯定等于某个 b[i]  i=[L;R].
同样的某个点i.最后肯定会被某个[L,R,b[i]]操作到.

令val=b[1] b[1]前面没有操作,显然我们想让后面更多b[j]=val被这一次操作到.
用一个单调队列来维护,队列中的元素x表示操作为[L,R,x]的可以进行到当前i.
若b[i]>b[j] 则队列中的b[j]显然不能在往后面操作.
若b[front]>a[i] a[i]不能变高,队头元素也不能往后操作.
此时若b[i]!=b[rear] 则当前位置要想变成b[i]必须新增一个操作(前面[l,r,x]的操作不可能跨到位置i)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,a[N],b[N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++)	cin>>a[i];
		for(int i=1;i<=n;i++)	cin>>b[i];
		bool flag=true;
		for(int i=1;i<=n;i++)	if(a[i]<b[i])	flag=false;
		if(!flag){
			cout<<-1<<'\n';
			continue;
		}
		deque<int> q;
		int res=0;
		for(int i=1;i<=n;i++){
			while(!q.empty()&&b[i]>q.back())	q.pop_back();
			while(!q.empty()&&a[i]<q.front())	q.pop_front();
			if(a[i]!=b[i]&&(q.empty()||b[i]!=q.back())){
				res++;
				q.push_back(b[i]);
			}
		}
		cout<<res<<'\n';
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值