CC April 18 Cutting Plants 單調佇列+思維
阿新 • • 發佈:2018-11-02
題意:長度為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; }