P1108 低價購買 題解

mountzhu發表於2024-09-19

這題在求最長下降子序列的基礎上加了一個求方案數的要求,這就讓這道題目變難了很多。
我們考慮我們在求最長下降子序列的時候,總是從這一位,要麼重新開始計數,要麼只和前面的有關,所以前面的資訊完全丟失了,無法判斷有多少方案,所以我們就要針對前面的方案數設計一個dp來統計。
可以稱之為dp套dp?
其實我們不難想到,對於方案數也具有最優子結構,也無後效性,可以轉移。
我們很自然地想到對於每一個可能的轉移點,如果這個轉移點是當前最優的,那麼我們就要將方案數改成它;如果相等,則累加。
但是這樣會有問題,即當相等時會讓後面的點向前掃的時候重複計數,所以我們直接選擇將其中一個的方案數變為0。

這道題就啟示我們不要被一些看起來不是很好想的唬到了,其實還是很好想的。

#include<bits/stdc++.h>
using namespace std;
int n;
long long a[5005],dp[5005],f[5005];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n;++i){
		for(int j=1;j<i;++j){
			if(a[i]<a[j]) dp[i]=max(dp[i],dp[j]+1);
		}
		if(!dp[i]) ++dp[i];
		for(int j=1;j<i;++j){
			if(dp[i]==dp[j]&&a[i]==a[j]) f[j]=0;
			if(dp[i]==dp[j]+1&&a[i]<a[j]) f[i]+=f[j];
		}
		if(!f[i]) f[i]=1;
	}
	long long maxi=0,num=0;
	for(int i=1;i<=n;++i) maxi=max(maxi,dp[i]);
	for(int j=1;j<=n;++j){
		if(dp[j]==maxi) num+=f[j];
	}
	printf("%lld %lld",maxi,num);
	return 0;
}

相關文章