poj1952(BUY LOW,BUY LOWER)(dp记录方案个数)

31 篇文章 0 订阅
2 篇文章 0 订阅

简单说一下题意,就是求最长递减子序列,并且!!!求出总共有多少个不同的最长子序列,比如
9
99 100 97 100 97 100 101 98 96
这组样例中的最长递减子序列长度为3,
(用pi表示位于第i个)
p2,p3,p9和p2,p5,p9和p4,p5,p9就只能算一个(因为都是100,97,96)。
刚做这道题也是没有什么思路,就直接先敲代码实现全部最长子序列个数(包括相同的),以下是这个的主要实现部分(非正确解法,要改进)

if(dp[i]!=1) cnt[i]=0;这个就是如果最长子序列不是1,那么它肯定是从前面来的,先置零

for(int i=2;i<=n+1;i++)
        { 
            for(int j=1;j<i;j++)
        if(price[j]>price[i]&&dp[i]<dp[j]+1) dp[i]=dp[j]+1;
            if(dp[i]!=1) cnt[i]=0;
            int tmp=0,tnt=0;
            for(int j=1;j<i;j++)
                if(price[j]>price[i]&&dp[i]==dp[j]+1) 
            cnt[i]+=cnt[j];

为什么讲这个呢?因为我发现只要在这个代码上改进以下就能得到ac代码。
注意,如果dp[i]是从前面来的,如果出现重复(比如上面i=9,重复就是3和5),那么一定!!!一定3和5一定是可能答案(比如这里的100 就不是可能答案,因为dp[4]=1,dp[4]

int tmp=0,tnt=0;
            for(int j=1;j<i;j++)
                {
                    if(price[j]>price[i]&&dp[i]==dp[j]+1) 
                        {   if(tmp!=price[j]) {cnt[i]+=tnt;tnt=0;}
                            tnt=max(tnt,cnt[j]);tmp=price[j];}
                }
            cnt[i]+=tnt;

如果觉得写的好,麻烦点一下赞,想了一个半小时。

ac代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <string.h>
#include <queue>
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
int cnt[5005],price[5005],dp[5005];
int main(int argc, char const *argv[])
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",price+i);
    price[n+1]=-1,dp[n+1]=cnt[n+1]=0;
    for(int i=1;i<=n;i++) cnt[i]=dp[i]=1;
    for(int i=2;i<=n+1;i++)
        { 
            for(int j=1;j<i;j++)
    if(price[j]>price[i]&&dp[i]<dp[j]+1) dp[i]=dp[j]+1;
            if(dp[i]!=1) cnt[i]=0;
            int tmp=0,tnt=0;
            for(int j=1;j<i;j++)
                {
                    if(price[j]>price[i]&&dp[i]==dp[j]+1) 
                        {   if(tmp!=price[j]) {cnt[i]+=tnt;tnt=0;}
                            tnt=max(tnt,cnt[j]);tmp=price[j];}
                }
            cnt[i]+=tnt;
        }
    printf("%d %d\n",dp[n+1]-1,cnt[n+1] );
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值