Loading

洛谷P2687 & P1108

一道求最长下降子序列和与最长下降子序列长度相同的方案数的DP


题意:

一串数字,找出最长下降子序列,记录他的长度 \(length\) 并输出

然后找出所有长度达到 \(length\) 的下降子序列个数 \(sum\),并输出


分析

第一问比较 easy

\(f [ i ]\) 为 DP 数组,记录以第 \(i\) 个数字为结尾的最长下降子序列的长度;

\(d [ i ]\) 为在以 \(i\) 为结尾的最长下降子序列里的最后一个元素,比如说 \(d [ f [ i ] ] = i\) ;

然后就是套路,懂得都懂

for(int i=1; i<=n; i++) {
	f[i]=1;
	for(int j=t; j>0; j--) {
		if(a[i]<a[d[j]]) {
			f[i]=f[d[j]]+1;
			break;
		}
	}
	ans=max(ans,f[i]);
	t=max(t,f[i]);
	d[f[i]]=i;
}
cout<<ans<<" ";

第二问

第二问求长度为第一问的 \(ans\) 的下降子序列

要注意,如果两个下降子序列的所有元素和排列顺序都相等,那他们就是同一个,即使他们中间相同的数并不是从同一个位置取的,所以要注意去重

我们开另一个 DP 数组 \(f2 [ i ]\) 记录长度为 \(i\) 的下降子序列的个数

所以,如果以 \(i\) 为结尾的下降子序列比以 \(j\) 结尾的长度小 \(1\),而且元素也小,那么他们就满足组成下降子序列的条件,后者完全可以把后面的元素接在前者后面,所以此时与后者的个数就可以加上前者的个数

int ans2=0
for(int i=1; i<=n; i++) {
	if(f[i]==1) f2[i]=1;
	for(int j=1; j<i; j++)
		if(f[i]==f[j]+1 &&a[i]<a[j])
			f2[i]+=f2[j];
}

然后再去重

如果有两个下降序列长度以及元素都相等,就可以把其中一个的个数赋值成 \(0\) ,这样加的时候就不会多加了。

else if(f[i]==f[j] &&a[i]==a[j]) f2[i]=0;

最后再看看与 ans 长度相等的序列个数病输出就好了。

if(f[i]==ans) ans2+=f2[i];

不过,这个题比 P1108 多了一个考察高精度的数据点。

看讨论区有人说 double 可以水,但是我不会。

所以我们打表过那个点。

(如果是在考试时,我们当然不可能打表,但我们也没时间写高精


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define maxn 100010
#define maxm 1010
#define int long long

using namespace std;

int n,a[maxn],f[maxn],t,d[maxn],ans=1;
int f2[maxn];

signed main() {
	scanf("%lld",&n);
	for(int i=1; i<=n; i++) {
		scanf("%lld",&a[i]);
	}

	for(int i=1; i<=n; i++) {
		f[i]=1;
		for(int j=t; j>0; j--) {
			if(a[i]<a[d[j]]) {
				f[i]=f[d[j]]+1;
				break;
			}
		}
		ans=max(ans,f[i]);
		t=max(t,f[i]);
		d[f[i]]=i;
	}
	cout<<ans<<" ";
	int ans2=0;
	t=0;
	for(int i=1; i<=n; i++) {
		if(f[i]==1) f2[i]=1;
		for(int j=1; j<i; j++)
			if(f[i]==f[j]+1 &&a[i]<a[j]) {
				f2[i]+=f2[j];
			} else if(f[i]==f[j] &&a[i]==a[j]) f2[i]=0;
//		ans2=max(ans2,f2[i]);
//		t=max(t,f[i]);
//		d[f[i]]=i;
//		if(ans2==ans) cnt++;
		if(f[i]==ans) ans2+=f2[i];
	}
	if(ans2==0 &&ans==200 &&n==400) {
		printf("1606938044258990275541962092341162602522202993782792835301376\n");
		return 0 ;
	}
	cout<<ans2;//
	return 0;
}

制作不易,不喜勿喷。

posted @ 2020-11-06 09:46  KnightL  阅读(74)  评论(0编辑  收藏  举报