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 */
寻找真正的热爱