P1108 低价购买(LIS和LIS计数)

题目链接:https://www.luogu.org/problemnew/show/P1108
动态规划:https://blog.csdn.net/weixin_39778570/article/details/87014343
ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443

本题很明显求最长的LIS,并且求出本质不同的LIS的数目
最长下降子序列
----------------------------------------------
使用O(n^2)方法求出LIS
dp[i],表示以a[i]结尾的最长严格下降序列 
j&i && a[i]<a[j], dp[i] = max(dp[i], dp[j]+1),
f[i] 表示选中a[i]长度为 dp[i] 的序列数(本质不同,并且与前面不重复) 
if(a[i]<a[j] && dp[j]+1==dp[i])f[i] += f[j];
else if(a[i]==a[j] && dp[i]==dp[j]) f[i] = 0; // 前面计算过了(此时没考虑j+1到i之间的数)
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 5006;
int n,a[maxn],dp[maxn],f[maxn];
void solve(){
	int ans1=0,ans2=0;
	fo(i,1,n){
		dp[i]=1; // 以a[i]结尾的最长严格下降序列 
		fo(j,1,i-1){
			if(a[j]>a[i]){
				dp[i] = max(dp[i], dp[j]+1);
			}
		}
		ans1 = max(ans1, dp[i]);
	}
	// f[i] 表示选中a[i]长度为 dp[i] 的序列数(本质不同,并且与前面不重复) 
	fo(i,1,n){
		if(dp[i]==1)f[i]=1;
		fo(j,1,i-1){
			if(a[i]<a[j] && dp[j]+1==dp[i])f[i] += f[j];
			else if(a[i]==a[j] && dp[i]==dp[j]) f[i] = 0; // 前面计算过了 
		}
	} 
	fo(i,1,n)if(ans1==dp[i]){
		ans2 += f[i];
	} 
	cout<<ans1<<" "<<ans2;
}
int main(){
	scanf("%d",&n);
	fo(i,1,n)scanf("%d",&a[i]);
	solve();
	return 0;
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页