XJOI 迷你火车头

来源:互联网 发布:jquery.form.js教程 编辑:程序博客网 时间:2024/04/29 20:32

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

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

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
原创粉丝点击