POJ 1952 DP

思路:

这题要求最长下降子序列的长度和个数,我们可以增加 数组maxlen[size](记录当前第1个点到第i个点之间的最长下降序列长度) 和maxnum[size](记录1~i之间的最长下降序列个数 ) ,首先对于最长下降序列属于DP基础题,只要对每一个a[i]求出符合要求(a[i] < a[j])的max( maxlen[j] + 1)即可,主要难点在第二步求下降序列总数

在序列中,如果maxlen[j]+1 == maxlen[i]则说明a[i]和a[j]在同一个下降数列中(显然必有a[i]< a[j]),那么我们只要将每一种符合要求的状态maxnum[j]转移到maxnum[i]中就可以了,有几个细节需要注意,题目要求序列是严格递减的,那么对于两个相同的数我们只能记录一个合法解,那么程序必须只记录两个相同数之间的状态,在这里用倒推可以简化编程,只要找到一个等于的就直接跳出循环,还要注意,如果从当前的a[i]一直找到相等的a[j]在这之间都没有可行状态的话,当maxnum[i]默认值为1要修改为0(避免错误计算),为0的当然无需处理。

转自:http://blog.csdn.net/zhang360896270/article/details/6701589

// by SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,a[5005],f[5005],ans=0,ans2=0,cnt[5005];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)f[i]=cnt[i]=1;
    for(int i=2;i<=n;i++)
        for(int j=i-1;j;j--)
            if(a[i]<a[j]){
                if(f[i]<f[j]+1)
                    f[i]=f[j]+1,cnt[i]=cnt[j];
                else if(f[i]==f[j]+1)
                    cnt[i]+=cnt[j];
            }
            else if(a[i]==a[j]){
                if(f[i]==1)
                    cnt[i]=0;
                break;
            }
    for(int i=1;i<=n;i++)
        if(ans<f[i])
            ans=f[i],ans2=cnt[i];
        else if(ans==f[i])
            ans2+=cnt[i];
    printf("%d %d",ans,ans2);
}
posted @ 2016-08-26 16:12  SiriusRen  阅读(157)  评论(0编辑  收藏  举报