洛谷 P2008 大朋友的数字 线性DP

题目描述

有一批大朋友(年龄 15 岁以上),他们每人手上拿着一个数字,当然这个数字只有 1 位,也就是 0 到 9 之间。每个大朋友的分数为在他之前的最长不下降子序列中所有数之和。(这个序列必须以它作为结尾!)如有多个最长不下降子序列,那么取编号字典序最小的。现在告诉你有 n 个大朋友,以及他们各自的数字,请你求出他们每个人的分数。

输入格式

第一行,1个数 n。

第二行,n 个数,分别表示每个人的数字。

输出格式

一行,n 个数,分别表示每个人的分数。

输入输出样例

输入 #1

5
1 2 5 3 4

输出 #1

1 3 8 6 10

输入 #2

5
1 7 5 9 6

输出 #2

1 8 6 17 12

 

说明/提示

【样例解释 1】

五个人分数分别为 (1),(1+2),(1+2+5),(1+2+3),(1+2+3+4)。

【样例解释 2】

五个人分数分别为 (1),(1+7),(1+5),(1+7+9) (还有一个 (1,5,9)),(1+5+6)。

【数据规模】

对于 50% 的数据,1≤n≤500;

对于 80% 的数据,1≤n≤10³;

对于 100% 的数据,1≤n≤104。

 

        线性DP模板题最长不下降子序列,用 f[i] 表示以 i 结尾的最长不下降子序列,用 q[i] 表示以 i 结尾的最长不下降子序列的和。

状态转移方程:

        从前往后枚举 i ,f[i] 初始长度至少为 1 ,再从前往后枚举 j 寻找 i 之前的所有方案,如果有 a[j] < a[i] ,那么 f[i] 必定可以在 j 的基础上加 1 ,最终与自身取最大值求解最优解,

即 f[i] = max(f[i],f[j]+1) ,同理,如果 f[i] 可以转移,那么最长上升子序列的和 q[i] 也可以转移,

即 q[i] = q[j] + a[i] 。

刚开始做的时候理解错了题意当作最长上升子序列来做,结果Wa了几次也没找到错误。

代码:

#include <iostream>
#include <cstdio>

using namespace std;

const int N=1e4+10;

int a[N];
int f[N];
int q[N];

int main()
{
	int n;
	scanf("%d",&n);
	
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		f[i]=1;
		for(int j=1;j<i;j++)
		{
			if(a[j]<=a[i])
			{
				if(f[i]<f[j]+1)
				{
					f[i]=f[j]+1;
					q[i]=q[j];
				}
			}
		}
		q[i]+=a[i];
	}
	
	for(int i=1;i<=n;i++) printf("%d ",q[i]);
	
	return 0;
}

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值