【tyvj1208】最长不下降子序列2

245 篇文章 0 订阅

描述

设有整数序列b1,b2,b3,…,bm,若存在i1<i2<i3<…<in,且bi1<bi2<bi3<…<bin,则称 b1,b2,b3,…,bm中有长度为n的不下降序列bi1,bi2,bi3,…,bin。求序列b1,b2,b3,…,bm中所有长度(n)最大不下降子序列
具有相同元素的序列,我们称之为重复序列,这里我们不统计重复序列,也即是说,重复的是算一次

输入格式

第一行为m,表示m个数(m<=900)
第二行m个数

输出格式

第一行输出最大长度n
第二行输出长度为n的序列个数Total

测试样例1

输入


1 2 2

输出


1
【题解】

题目描述的是最长上升子序列

至今仍然觉得这道题的思路很奇怪。在序列的后面加一个极大的数,其实这是用来存答案的。然后做最长上升,做完之后寻找答案的过程其实还是一个dp,由前面的点去扩展后面的点。但是要注意的是,如果当前点和后面有一个点重复,那么直接退出防止多算(因为对于后面的数来说,前面有两个一样的是没有影响的)

其实也就是说用离他最近的那一个符合条件的点去扩展他。

要注意不能把相同的数的前面那个删去。反例比如说13235。但是把相邻的相同的数删掉是完全可以的。

这道题隔一段时间应该看一看。但是还是觉得时间复杂度十分的不科学

【代码】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define inf 2100000000
using namespace std;
int n1,n,Max;
int f[1005],a[1005],h[1005],ans[1005];
bool b[1005];
int main(){
	scanf("%d",&n1);
	for (int i=1;i<=n1;++i) scanf("%d",&a[i]);
	for (int i=2;i<=n1;++i)
	  if (a[i]==a[i-1]) b[i]=true;
	n=0;
	for (int i=1;i<=n1;++i)
	  if (!b[i]) h[++n]=a[i];
	h[++n]=inf;
	f[1]=1;
	for (int i=2;i<=n;++i){
		for (int j=1;j<i;++j)
		  if (h[i]>h[j]&&f[i]<f[j])
		  	f[i]=f[j];
		f[i]++;
	}
	for (int i=1;i<=n;++i)
	  Max=max(f[i],Max);
	for (int i=1;i<=n;++i) if (f[i]==1) ans[i]=1;
	for (int i=1;i<=Max;++i)
	  for (int j=i;j<=n;++j)
	    if (f[j]==i)
	      for (int k=j+1;k<=n;++k){
	      	if (f[k]==f[j]+1&&h[k]>h[j])
	      	  ans[k]+=ans[j];
	      	if (h[k]==h[j]) break;
	      }
	Max--;
	printf("%d\n%d\n",Max,ans[n]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值