標籤:tchar lse 問題 個數 stdin freopen 就是 簡單的 nlogn
noname
【問題描述】
給定一個長度為n的正整數序列,你的任務就是求出至少需要修改序列中的多少個數才能使得該數列成為一個嚴格(即不允許相等)單調遞增的正整數序列,對序列中的任意一個數,你都可以將其修改為任意的正整數。
【輸入格式】
每個測試點第一行為一個正整數T,表示該測試點內的資料群組數,你需要對該測試點內的T組資料都分別給出正確的答案才能獲得該測試點的分數。
接下來T組資料,每組資料第一行一個正整數n,表示序列長度,接下來一行n個正整數描述這個序列。
【輸出格式】
對於每一組測試資料輸出一行一個非負整數表示答案。
【輸入輸出範例】
noname.in |
noname.out |
4 3 1 1 2 3 2 2 3 4 1 2 3 4 4 2 3 3 4 |
2 1 0 2 |
【範例解釋】
第一組資料中,由於正整數的限制,只能修改序列中第2、3個數。
第二組資料中,將第一個數修改為1即可。
第三組資料已經符合條件,不需要修改。
第四組資料中,由於正整數的限制,只修改一個數並不能完成任務,而需要同時修改前兩個數或者後兩個數。
【資料規模與約定】
對於30%的資料,有1≤n≤10。
對於80%的資料,有1≤n,T≤50,且輸入序列中每個數均不超過50。
對於100%的資料,有1≤n≤50000,1≤T≤5000,輸入序列中每個數均為不超過1000000000(10^9)的正整數,且每個測試點中T組資料對應的n值總和不超過500000。
【題解思路】
這題看著怎麼這麼像LIS啊?(:霧
回顧一下dp入門題LIS ?
依稀記得這題是可以二分最佳化的吧:O(n^2) à O(nlogn)
我們思考類型題:
- 把一個序列改成非嚴格單調遞增的(單調不下降的),至少需要修改多少個數?
A:用該序列總長度減去最長不下降子序列的長度。
2.那麼把一個序列改成嚴格單增的呢?
A:用該序列總長度減去最長上升子序列的長度?標準錯答案啊。
正解是:構造序列B[i] = A[i] – i;答案即為序列總長度減去B的最長不下降子序列。
Why??? 因為要求嚴格單調遞增,所以前一項與後一項至少相差一,將這個必要的差值減去,就相當於求B改成非嚴格單增最少需修改的數,也就相當於第一個問題。
3.(本題)在2的條件下把整數改成了正整數。題目意思就變成:求首項為非負整數的最長上升子序列。
那豈不是很簡單的一個dp ???當然還是需要二分最佳化的啦。
#include<bits/stdc++.h> using namespace std;const int maxx= 100001;int a[maxx],b[maxx],n,T,f[maxx],len;inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;}int find(int x){ int l = 1,r = len + 1; if(x < f[1])return 0; while(l+1 < r){ int m = l + r>>1; if(f[m] <= x) l=m; else r = m; } return l;} void work(){ len = 0; for(int i = 1;i <= n;i++){ if(b[i] < 0)continue; int id = find(b[i]); len = max(id + 1,len); f[id+1] = min(f[id+1],b[i]); } printf("%d\n",n-len);} int main(){ freopen("noname.in","r",stdin); freopen("noname.out","w",stdout); T = read(); while(T--){ n = read(); memset(f,0x3f,sizeof(f)); for(int i = 1;i <= n; ++i){ a[i] = read(); b[i] = a[i] - i; } work(); } return 0;}
noip類比【noname】