線性dp+最長遞增子序列思想 數列(洛谷 P1799)

數列

題目描述

雖然msh長大了,但她還是很喜歡找點遊戲自娛自樂。有一天,她在紙上寫了一串數字:1,l,2,5,4。接着她擦掉了一個l,結果發現剩下l,2,4都在自己所在的位置上,即1在第1位,2在第2位,4在第4位。她希望擦掉某些數後,剩下的數列中在自己位置上的數儘量多。她發現這個遊戲很好玩,於是開始樂此不疲地玩起來……不過她不能確定最多能有多少個數在自己的位置上,所以找到你,請你幫忙計算一下!

輸入格式

第一行爲一個數n,表示數列的長度。

接下來一行爲n個用空格隔開的正整數,第i行表示數Ai。

輸出格式

一行一個整數,表示擦掉某些數後,最後剩下的數列中最多能有多少個數在自己的位置上,即Ai=i最多能有多少。


非常巧妙的一道題,刪去一個數,在這個數位置後面的數往前走一個位,可以發現最後答案一定是一個遞增的序列(這裏指Ai=i的元素),在Ai=iA_i=iAj=jA_{j}={j}之間的元素只是起到了填充的作用,不用管它的值是什麼;

所以dp方程就特別好理解:

if(dp[j]&&a[i]>a[j]&&a[i]-a[j]<=i-j) dp[i]=max(dp[i],dp[j]+1);

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=2010;
const int M=50100;
const LL mod=10007;
int a[1100],dp[1100];
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	int ans=0;
	for(int i=1;i<=n;i++){
		if(i>=a[i]){
			dp[i]=1;
			for(int j=1;j<i;j++){
				if(dp[j]&&a[i]>a[j]&&a[i]-a[j]<=i-j) dp[i]=max(dp[i],dp[j]+1);
			}
		}
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章