1. 程式人生 > >5773 The All-purpose Zero LIS變形 思維+dp

5773 The All-purpose Zero LIS變形 思維+dp

題目連結

題意:

可以將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;
}