5773 The All-purpose Zero LIS變形 思維+dp
阿新 • • 發佈:2018-12-24
題意:
可以將0替換成任意interger(包括負數),在此基礎上求最長遞增子序列。
思路:
對於這個題目,我只想%一下出題大佬!
首先要知道,把所有的0都用上一定不會使答案變得更差.
這個題目確實有助於你理解nlogn複雜度求LIS的演算法,dp[i]陣列儲存的就是當前LIS長度為i的末尾最小的一個數,
那麼舉個例子 1 2 3 0 0 4.
我們拋開別的長度不說了吧,就只說說長度為3。
長度為3的最後一個最小的是3,那麼新增加一個0的話,長度為4結尾的最小就為4了,也就是dp【3】+1.
長度為5的,就是dp【4】+1,因為這裡是嚴格遞增,那麼再來一個4的話,已經無法加入是答案變得更好了.
那麼我們發現有一個0的話就是使最優的那個+1,從反面來考慮就相當於當前0後面所有非0的數都-1,這樣所有0後面的都減1得到的LIS沒有影響.
所以這個題目就是把所有的0拿出來,對於每一個非0的就減去前面所有0的個數,對所有非0的數求一個LIS,然後+0的個數即可.
PS:可能舉的例子不合適,需要自己好好理解了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=1e5+10; int dp[maxn],b[maxn]; int n; int main(){ int ca = 1; int _; cin>>_; while(_--) { memset(dp,0,sizeof dp); cin>>n; int cnt = 0; int len = 0,a; for(int i=1; i<=n;i++) { scanf("%d",&a); if(a == 0) cnt++; else { a-=cnt; b[len++]=a; } } int ta = 0; for(int i = 0;i < len;i++) { if(ta == 0 || b[i] > dp[ta]) dp[++ta] = b[i]; else { int tmp = lower_bound(dp+1,dp+1+ta,b[i]) - dp; dp[tmp] = min(dp[tmp],b[i]); } } printf("Case #%d: %d\n",ca++,ta+cnt); } return 0; }