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;
}