poj 1952 BUY LOW, BUY LOWER dp

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值