這不是一道簡單的求最長下降子序列的問題。因爲我們還需要求不相同的方案數目,而求方案數目也是一個dp的過程。
我們使用來表示到以個元素結尾的最長下降子序列的長度,表示以個元素結尾的最長下降子序列的組合數目,表示第個元素。那麼我們可以得到如下的性質
- 如果,那麼,當然也可能有重複元素,極端一點比如
1,1,1,1,1
,我們最終的結果的組合數要是1,所以這道題的一大難點在於如何去重。 - 考慮,也就是說以元素結尾的序列是從以結尾的序列派生出來的,那麼我們有,有多少種組合數,我們就能相應的生成多少種。
- 如果一個數列的第一個數與另一個數列的第一個數相同,那麼現在可以判斷它們相等,即可以把其中一個刪掉,即,當不同的數接在它的後面時,又可以將它們判斷爲兩個數列,這是不互相影響的。因爲兩個數列都可以由這個相等的數列轉移而來。也就是說我們總是在第一個元素的位置考慮去重,排除所有一開始就相等的元素,那麼之後接上的序列總是不相等的。
if (a[i] < a[j] && dp[j] + 1 == dp[i])
c[i] += c[j];//i的組合數和j有關
else if (dp[i] == dp[j] && a[i] == a[j])
c[i] = 0;//去重,避免完全相同的方案
#define ll long long
#define inf 0x3ffffff
#define MAX 5005
#define vec vector<ll>
int main() {
ll N, a[MAX], dp[MAX], c[MAX];
while (cin >> N) {
memset(dp, 0, sizeof(dp));
memset(c, 0, sizeof(c));
ll maxx = 0, cnt = 0;
for (int i = 1; i <= N; i++)cin >> a[i];
for (int i = 1; i <= N; i++) {
dp[i] = 1;
for (int j = i - 1; j >= 1; j--) {
if (a[i]<a[j] && dp[j] + 1 > dp[i])
dp[i] = dp[j] + 1;
}
if (dp[i] == 1)c[i] = 1;//不能組成序列,只有一種組合數
//注意這個方向是從1-i,而不能從i-1
for (int j = 1; j < i; j++) {
if (a[i] < a[j] && dp[j] + 1 == dp[i])
c[i] += c[j];//i的組合數和j有關
else if (dp[i] == dp[j] && a[i] == a[j])
c[i] = 0;//去重,避免完全相同的方案
}
if (dp[i] > maxx)maxx = dp[i];
}
for (int i = 1; i <= N; i++)
if (dp[i] == maxx)cnt += c[i];
cout << maxx << ' ' << cnt << endl;
}
}