XJOI 迷你火车头

题目描述
一列火车有一个火车头拖着一长串的车厢,每个车厢有若干个乘客。一旦火车头出了故障,所有的车厢就只能停在铁轨上了,因此铁路局给每列火车配备了三个迷你火车头,每个迷你火车头可以拖动一定数量的车厢,以便火车头发生故障后能够拖走部分车厢。

铁路部门对迷你火车头作了如下规定:

1.迷你火车头能够拖动的最大车厢数是确定的,这个数量对三个迷你火车头都是相同的。

2.一旦火车头发生故障,迷你火车头要拖走尽可能多的旅客,每节车厢的旅客数事先是已知的,并且旅客不得随意更换车厢。

3.一个迷你火车头拖走的车厢必须是连续的,所有车厢从1开始编号。

假如有7节车厢,一个迷你火车头最多可以拖动二节车厢,1到7号车厢中的旅客人数分别为35,40,50,10,30,45和60。

如果三个迷你火车头拖走的车厢分别是1-2,3-4和6-7,它们带走的旅客总数将达到240人,其它任何方案都不可能超过该数,所以240就是这个问题的解。

给定车厢数,每节车厢的旅客人数和一个迷你火车头能拖动的最大车厢数,写一个程序求出三个迷你火车头最多能带走的旅客数。

输入

输入文件共有三行,第一行为一个正整数n,其中n<=50,000,表示车厢总数,第二行为n个用空格隔开的整数,依次表示n节车厢的旅客人数,每节车厢人数不超过100,第三行为一个正整数m表示迷你火车头能够拖动的最大车厢数,其中m<=n/3。

输出

输出文件仅有一行包含一个整数表示三个迷你火车头最多能带走的旅客数。

样例

样例输入:

7

35 40 50 10 30 45 60

2

样例输出:

240

据说这是个暴力枚举+贪心的水题然而我还是中规中矩的打了DP。。。。。。
贪心的做法:题目等同于选取三个区间,从而使这三个区间和最大。那么显然三个区间不互相覆盖一定是最优的(因为没有负数)。那么我们从第k+1个到第n-k+1枚举中间的火车就好。什么?TLE?没关系!对于整个数组,我们维护一个前缀和,维护一个后缀和,这样我们就能在O(n)的时间内得出答案(常数当然不算)。
DP做法:先预处理出一个小火车头在第i个地点所能载得的人数,然后我们开一个二维dp数组,第一维记录位置,第二维记录第几个小火车头。因为我们有一个小火车头能载得的人数,那么我们能优先处理出dp[i][1]来,这样我们就只需要dp出第二和第三个小火车头就行了。方程也很容易写出:dp[i][j]=max(dp[i-1][j],dp[i-k][j-1]+w[i])
DP的代码

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 55000;
int n,k,a[maxn],dp[maxn][4],w[maxn];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&k);
    for (int i=1;i<=k;i++) w[1]+=a[i];
    for (int i=k+1;i<=n;i++) w[i-k+1]=w[i-k]-a[i-k]+a[i];
    for (int i=1;i<=n-k+1;i++) dp[i][1]=max(dp[i-1][1],w[i]);
    for (int j=2;j<=3;j++)
    for (int i=k*(j-1)+1;i<=n-k+1;i++) 
        dp[i][j]=max(dp[i-1][j],dp[i-k][j-1]+w[i]);
    printf("%d\n",dp[n-k+1][3]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值