Educational Codeforces Round 39 (Rated for Div. 2) G
阿新 • • 發佈:2018-03-22
div 線段樹 離散化 fin problems 子序列和 def down name 個數 前面的數做變換\(a_i - i (i < k)\), 後面的數做變換\(a_i - (i-1) (i > k)\)
我們計算以k-1結尾的最長不下降子序列和後面某個\(a_j(a_j >= a_{k-1})\)起始的最長不下降子序列拼接起來得到的長度,更新答案即可
先離散化處理
維護以\(a_i\)結尾的的最長不下降子序列的長度和以\(a_i\)開始的最長不下降子序列的長度
假設先從後往前處理,可以處理出後綴,同時也可以計算出每個數要拼接的最長後綴的長度,再從前往後處理算出前綴,更新答案即可。
用線段樹維護 復雜度\(O(nlogn)\)
Educational Codeforces Round 39 (Rated for Div. 2) G
題意:
給一個序列\(a_i(1 <= a_i <= 10^{9}),2 <= n <= 200000\), 如果至多刪除其中的一個數之後該序列為嚴格上升序列,那麽稱原序列為幾乎嚴格上升序列。
現在每次將序列中的任意數字變成任意數字,問最少要操作幾次才能將序列變成幾乎嚴格上升子序列。
思路:
如果不考慮刪除,求讓整個序列都變成嚴格上升子序列的次數
求出\(序列a_i - i\)的最長不下降子序列的長度\(len\), \(n - len\)就是答案
現在來考慮刪除一個數的情況
我們枚舉刪除第\(k\)
我們計算以k-1結尾的最長不下降子序列和後面某個\(a_j(a_j >= a_{k-1})\)起始的最長不下降子序列拼接起來得到的長度,更新答案即可
先離散化處理
維護以\(a_i\)結尾的的最長不下降子序列的長度和以\(a_i\)開始的最長不下降子序列的長度
假設先從後往前處理,可以處理出後綴,同時也可以計算出每個數要拼接的最長後綴的長度,再從前往後處理算出前綴,更新答案即可。
用線段樹維護 復雜度\(O(nlogn)\)
#include<bits/stdc++.h> #define LL long long #define P pair<int,int> using namespace std; const int N = 4e5 + 10; int a[N]; vector<int> b; int n,nn; int dppre[N],dpsuf[N],sufmx[N]; int mx[N << 2]; void update(int pos,int val,int l,int r,int rt){ if(l == r){ mx[rt] = max(mx[rt],val); return ; } int m = l + r >> 1; if(pos <= m) update(pos,val,l,m,rt<<1); else update(pos,val,m+1,r,rt<<1|1); mx[rt] = max(mx[rt << 1], mx[rt << 1|1]); } int querymx(int L,int R,int l,int r,int rt){ if(L <= l && R >= r) return mx[rt]; int ans = 0; int m = l + r>>1; if(L <= m) ans = max(ans, querymx(L, R, l, m, rt<<1)); if(R > m) ans = max(ans, querymx(L, R, m + 1, r, rt<<1|1)); return ans; } /* 10 5 6 7 8 9 5 10 11 12 13 */ int main(){ cin>>n; for(int i = 1;i <= n;i++){ scanf("%d",a + i); b.push_back(a[i] - i); b.push_back(a[i] - i + 1); } sort(b.begin(), b.end()); b.erase(unique(b.begin(),b.end()),b.end()); nn = b.size(); for(int i = n;i >= 1;i--){ int pos = lower_bound(b.begin(), b.end(), a[i-1] - i+1) - b.begin() + 1; if(i == 1) pos = 1; sufmx[i-1] = querymx(pos, nn, 1, nn, 1); pos = lower_bound(b.begin(), b.end(), a[i] - i + 1) - b.begin() + 1; int v = querymx(pos, nn, 1, nn, 1); dpsuf[i] = v + 1; update(pos, dpsuf[i], 1, nn, 1); //cout<<i - 1<<" "<<sufmx[i - 1]<<" "<<v + 1<<endl; } for(int i = 1;i <= (nn<<2);i++){ mx[i] = 0; } int ans = sufmx[0]; for(int i = 1;i <= n;i++){ int pos = lower_bound(b.begin(), b.end(), a[i] - i) - b.begin() + 1; int v = querymx(1, pos, 1, nn, 1); dppre[i] = v + 1; ans = max(dppre[i] + sufmx[i], ans); //cout<<i<<" "<<dppre[i]<<" "<<sufmx[i]<<endl; update(pos, dppre[i], 1, nn, 1); } cout<<max(0,n - 1 - ans)<<endl; return 0; }
Educational Codeforces Round 39 (Rated for Div. 2) G