洛谷1108低价购买(动态规划练习题)

时间:2021-04-10 00:10:16

题目:https://www.luogu.org/problemnew/show/1108


思路:

这题有两种方法,第一种用动态规划,另一种用二分答案,这里介绍的是动态规划方法。

首先这题其实就是最长下降序列+统计方案数

a[i]表示第i种股票

b[i]表示前i个数的最长下降序列长度

f[i]表示到b[i]的方案个数

如果(b[j]+1=b[i])and(a[i]<a[j]) 也就是满足不下降且可以到达这里,那么f[i]=f[i]+f[j];但是我们会发现,如果前面有两种价格相等的股票,且到这两种股票的最长下降序列长度相等,也就是方案重复,那么此时的f[j]=0;

动态转移方程

f[i]+=(a[i]<a[j]&&b[j]+1==b[i])?f[j]:(a[i]==a[j]&&b[i]==b[j])?-f[i]:0;


废话不多说,上代码!

#include<cstdio>
#include<cstring>
#define k freopen
#define r(i,a,b) for (int i=a;i<=b;i++)//循环 
using namespace std;int n,ans1,ans2;//ans1是最长下降序列的长度,ans2是方案数
long long a[5001],b[5001],f[5001];//前面已经解释过了
int max(int x,int y)//推荐还是自己定义比较好
{
	return x>y?x:y;
}
void LRZ()//输入
{
	ans1=1;
	scanf("%d",&n);
	r(i,1,n)
	 scanf("%d",&a[i]),b[i]=1;//最长下降
}
void LDS()//b[i]的值,用于理解 
{
	r(i,1,n)
	 printf("%d ",b[i]);
}
void dp()
{
	r(i,1,n)
	 {
	 	r(j,1,i-1)
	 	 if (a[j]>a[i]&&b[j]+1>b[i])//先把到i的最长下降序列求下来
	 	 {
	 	 	b[i]=b[j]+1;
	 	 	ans1=max(ans1,b[i]);//取下最大值
	 	 }
	 	if (b[i]==1) f[i]=1;//如果它的长度是1,那么它的方案数也是一,因为没有长度为0的序列
	    r(j,1,i-1)//从1到i-1
	     f[i]+=(a[i]<a[j]&&b[j]+1==b[i])?f[j]:(a[i]==a[j]&&b[i]==b[j])?-f[i]:0;//动态转移
	 }
}
void print()
{
	printf("%d ",ans1);
	r(i,1,n)
	 if (b[i]==ans1)
	  ans2+=f[i];//把所有的方案加在一起
	printf("%d",ans2);//输出
}
int main()
{
	LRZ();
	dp();
	print();
}