传送门:hdu 5087
总结起来题目意思就是给定一个长度为n的数组,找出次长的最长递增子序列的长度(次长与最长允许相等)
这里n的范围只到1000,因此O(n^2)的算法也可过,比赛时候卡了好久在想O(nlogn)的....(>.<)
用dp[i]记录以位置i为末尾时的最大长度,dp2[i]记录以位置i为末尾的次大长度,dp求出所有i的dp[i]与dp2[i],并在同时更新最大长度与次大长度,最后直接输出次大长度即可。
/******************************************************
* File Name: 5087.cpp
* Author: kojimai
* Create Time: 2014年11月01日 星期六 22时41分42秒
******************************************************/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 1005
int a[FFF],dp[FFF],dp2[FFF];
int getans(int i,int j)//以j为末尾的递增子序列的最大长度更新新长度
{
if(a[i] < a[j])
return 0;
else if(a[i] == a[j])//相等时构成长度相同
return dp[j];
else//比a[j]大时构成的新长度+1
return dp[j] + 1;
}
int getans2(int i,int j)//以j为末尾的递增子序列的次大长度更新新长度
{
if(a[i] < a[j])
return 0;
else if(a[i] == a[j])
return dp2[j];
else
return dp2[j] + 1;
}
int main()
{
int keng;
scanf("%d",&keng);
while(keng--)
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&a[i]);
memset(dp,0,sizeof(dp));
memset(dp2,0,sizeof(dp2));
dp[0] = 1;
int one = 1,second = 0;//one当前求得的最大长度,second为次大长度
for(int i = 1;i < n;i++)
{
dp[i] = 1;
//cout<<" i = "<<i<<endl;
for(int j = 0;j < i;j++)
{
int tmp = getans(i,j);
// cout<<" tmp1 = "<<tmp;
if(tmp > dp[i])
{
dp2[i] = dp[i];
dp[i] = tmp;
}
else if(tmp > dp2[i])
dp2[i] = tmp;
tmp = getans2(i,j);
// cout<<" tmp2 = "<<tmp<<endl;
if(tmp > dp2[i])
dp2[i] = tmp;
}
//cout<<" dp = "<<dp[i]<<" "<<dp2[i]<<endl;
if(one < dp[i])
{
second = one;
one = dp[i];
}
else if(second < dp[i])
{
second = dp[i];
}
if(second < dp2[i])
second = dp2[i];
}
cout<<second<<endl;
}
return 0;
}
原文地址:http://blog.csdn.net/u010535824/article/details/40690065