CodeForces - 1437E Make It Increasing 线段树动态开点
https://codeforces.com/problemset/problem/1437/E
这是有限制的最长上升子序列
数字之间必须满足list[i] - list[j] >= i - j
处理的时候就是让list[i] - i,这样就得到了最长不下降子序列,非正数就赋成INF忽略不计,就可以算了,见到大佬门用upper_bounder算的,不太会
我就用权值线段树动态开点写了这个题,转换成最长不下降子序列最重要!!!
具体看代码,不好写但是原理很简单
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1e6+1111;
typedef long long ll;
ll len = 3e9+11;
struct Node{
int l,r,ans;
}tree[maxn*10];
ll INF = 2e9+3;
int cnt = 0;
int update(int& node,ll be,ll en,ll i,int val){
if(node == 0) node = ++cnt;
int mid = be + en >> 1;
if(be == en){
tree[node].ans = val;
return 0;
}
if(i <= mid) update(tree[node].l,be,mid,i,val);
else update(tree[node].r,mid+1,en,i,val);
int l = tree[node].l;
int r = tree[node].r;
tree[node].ans = max(tree[l].ans,tree[r].ans);
return 0;
}
int ask(int node,ll be,ll en,ll LL,ll RR){
if(node == 0) return 0;
int mid = be + en >> 1;
if(LL <= be && en <= RR) {
return tree[node].ans;
}
int val1 = -1,val2 = -1;
if(LL <= mid) val1 = ask(tree[node].l,be,mid,LL,RR);
if(RR > mid) val2 = ask(tree[node].r,mid+1,en,LL,RR);
return max(val1,val2);
}
ll list[maxn];
int ins[maxn];
ll cns[maxn];
int dp[maxn];
int n,k;
int init(){
for(int i=0;i<=cnt;i++){
tree[i].l = tree[i].r = 0;
tree[i].ans = 0;
}
cnt = 2;
return 0;
}
int cal(int l,int r,int f){
int root =1;
cnt = 2;
int ans = 0;
int be = l + 1,en = r;
int len = 2e9;
for(int i=be;i<=en;i++){
cns[i] = list[i] - list[l] - (i - be);
if(cns[i] <= 0) {
cns[i] = INF;
ans++;
}
}
ans = 0;
for(int i = be;i<=en;i++){
if(cns[i] == INF) continue;
int a = ask(root,1,len,1,cns[i]);
dp[i] = a+1;
ans = max(ans,dp[i]);
update(root,1,len,cns[i],dp[i]);
}
for(int i=0;i<=cnt;i++){
tree[i].l = tree[i].r = tree[i].ans = 0;
}
if(f) return r - l - ans;
return r - l - dp[en];
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&list[i]);
}
list[0] = -1000000002;
int f = 0;
for(int i=1;i<=k;i++){
scanf("%d",&ins[i]);
}
for(int i=2;i<=k;i++){
int x = ins[i];
int y = ins[i-1];
if(list[x] - list[y] < x - y){
f = 1;
break;
}
}
if(f){
printf("-1\n");
return 0;
}
if(k == 0){
int ans = cal(0,n,1);
cout<<ans<<endl;
return 0;
}
int ans = 0;
for(int i=2;i<=k;i++){
ans += cal(ins[i-1],ins[i],0);
}
ans += cal(ins[k],n,1);
ans += cal(0,ins[1],0);
cout<<ans<<endl;
return 0;
}
/*
100 0
4 20 52 2 7 36 8 73 9 99 13 19 14 89 32 2 6 2 16 21 47 22 66 23 25 95 28
4 29 64 30 31 7 48 32 51 35 37 77 57 40 42 56 40 43 44 46 13 47 12 48 49
24 51 69 53 54 98 21 57 59 61 62 52 63 30 68 32 69 39 8 67 71 59 72 81 76
77 11 82 85 14 83 33 86 89 89 90 43 96 91 31 93 69 58 94 45 96 2 99
输出 80
*/
寻找真正的热爱

浙公网安备 33010602011771号