Codeforces-977F Consecutive Subsequence

cf的第一場div3!

並沒有熬夜去打。因爲想摸清大概難度。下午信息課時直接看了F題。

題目鏈接:http://codeforces.com/problemset/problem/977/F

看到標題就知道是一道最長上升子序列題。立馬想到要用dp,然後立即着手去寫。

但是測樣例是卻發現出現了問題,仔細一看才發現我忽略了一個重要的條件:序列是連續的。

然後很快改進代碼。提交。

#include<bits/stdc++.h>
using namespace std;

int n;
int a[200002];
int dp[200002],last[200002];
int tmp;

void solve(int n){
	if (n==-1) return;
	solve(last[n]);
	printf("%d ",n+1);
	return;
}

int main(){
	scanf("%d",&n);
	for (int i=0;i<n;i++) scanf("%d",&a[i]);
	memset(last,-1,sizeof(last));
	for (int i=0;i<n;i++) dp[i]=1;
	for (int i=1;i<n;i++) 
		for (int j=0;j<i;j++) if (a[j]==a[i]-1) {
			if (dp[j]+1>dp[i]){
				dp[i]=dp[j]+1;
				last[i]=j;
			}
		}
	int ans=0,Ans=0;
	for (int i=0;i<n;i++) {
		if (dp[i]>ans) {
			ans=dp[i];
			Ans=i;
		}
	}
	printf("%d\n",ans);
	solve(Ans);
	return 0;
}

沒錯,然後我就t5了。

看了下數據範圍:2*10^5,O(n^2)的時間複雜度確實肯定要tle

但是想了半天沒想到優化的方法?因爲上課老師講過最長上升子序列的dp解法,沒有其他優化的方法了啊?

這是突然想到,這道題的獨特之處:序列需連續

那麼解法就顯而易見了:dp[i]代表以i結尾的序列的最大長度。從前往後刷新。這樣只需一個循環。狀態轉移方程是dp[i]=max(dp[i],dp[i-1]+1)O(n)的複雜度,2s的時間限制綽綽有餘。

然後就可以找到dp[i]的最大值即最長長度。然後從初始序列的最後開始,從最長上升子序列的最後一個數字開始找其相應的位置,每找到一個,期望值-1(貪心:從最後往前找必定是最優解)PS感覺表述很不清楚但是看了代碼應該就懂了?

但還需注意:dp不能直接開數組!如果直接寫int dp[1000000000]會報錯!!!因爲數組太大了!!!所以這是就需要用map。10^9 int已經足夠。

AC代碼如下:

#include<bits/stdc++.h>
using namespace std;

int n;
int a[200002];
int cnt=0,last;
vector<int> ans;
map <int,int> dp;

int main(){
	scanf("%d",&n);
	for (int i=0;i<n;i++) scanf("%d",&a[i]);
	dp[a[0]]=1;
	for (int i=1;i<n;i++) 
		if (dp[a[i]-1]+1>dp[a[i]])
			dp[a[i]]=dp[a[i]-1]+1;
	for (int i=0;i<n;i++) {
		if (dp[a[i]]>cnt) {
			cnt=dp[a[i]];
			last=a[i];
		}
	}
	printf("%d\n",cnt);
	for (int i=n-1;i>=0;i--) {
		if (a[i]==last){
			ans.push_back(i+1);
			last--;
		}
	}
	for (int i=ans.size()-1;i>=0;i--) printf("%d ",ans[i]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章