http://poj.org/problem?id=1952
题意:给你一场数字,问最长下降子序列的长度n,和长度为n的不同下降子序列的个数,只要序列中每个元素都相同,就认为两个子序列是相同的。
思路:第一问很好解决,就是一个经典的LIS问题,主要就在于第二问,其实我们可以很据dp值向前推,只要对于i<j,只要a[i]<a[j]&&dp[i]==dp[j]-1,则j就由可能是由i推出的,所以将所有的i的可能的情况数加起来就是j的情况数,可是怎么判重呢?仔细想想,如果有两个相同大小的a[i]可以推出j的值,那么应该怎么做呢,其实我们可以忽略除了最大的i之外的所有i,因为前面的i的所有的可能情况,后面的i可会有,此时就会出现重复的情况,所以只要忽略除了第一个i之外所有的相同的i就可以了,用一个map来记录i是否出现过就可以了。代码如下。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
int dp[5010];
int a[5010];
int vis[5010];
int dfs(int x){
if(vis[x]) return vis[x];
if(dp[x]==1) return 1;
int ans=0;
map<int,int>s;
for(int i=x-1;i>=0;i--)
if(a[i]>a[x]&&dp[i]==dp[x]-1&&s[a[i]]==0){
ans+=dfs(i);
s[a[i]]++;
}
return vis[x]=ans;
}
int main()
{
int n;
while(cin>>n){
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++) if(a[i]<a[j])
dp[i]=max(dp[i],dp[j]+1);
}
int ans=0,num=0;
for(int i=0;i<n;i++)
ans=max(ans,dp[i]);
map<int,int>s;
for(int i=n;i>=0;i--){
if(dp[i]==ans&&s[a[i]]==0) {
num+=dfs(i);
s[a[i]]++;
}
}
cout<<ans<<' '<<num<<endl;
}
return 0;
}