N个城市,每个城市有一些金币,现在A,B两个人在同一个起点P,每人每秒可以从城市i移动到城市i+1或者i-1,并且任何时刻两人的距离不能超过M,求时间T内,两人最多能拿到多少金币。按照题意直接模拟就行,思路不难,代码挺蛋疼,好多细节的地方要考虑。考虑到每个城市的钱只能拿一次,那么两人如果往一个方向走是没意义的,所以一开始两人从起点向两侧走,直到距离为M,或者是时间耗尽了,如果时间耗尽,直接输出答案把,否则考虑在剩下的时间中如何去拿剩下的金币,三种情况,左边尽可能拿完再回来拿右边的;右边尽可能拿完再回来拿左边的;左边拿一部分,掉头去右边拿一部分;仔细想想前两种情况是可以归到最后一种情况里的,所以在这里两次枚举,第一次枚举左边到达的点,处理出先向左到达该店,再掉头最远能到右边的位置,拿这个区间的和来更新答案;第二次枚举右边到达的点,处理出先向右到达该点再向左最远能到哪个位置,同样用这个区间和来更新答案。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
typedef long long ll;
using namespace std;
int a[220000];
ll sum[220000];
int n,m,k,p,q,t;
ll find(int l,int r,int t)
{
ll res=0;
for (int k=r; k<=n; k++)
{
if (t-(k-r)*2<0) break;
int kl=l-(t-(k-r)*2);
kl=max(1,kl);
res=max(res,sum[k]-sum[kl-1]);
}
for (int k=l; k>=1; k--)
{
if (t-(l-k)*2<0) break;
int kr=r+(t-(l-k)*2);
kr=min(kr,n);
res=max(res,sum[kr]-sum[k-1]);
}
return res;
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&p))
{
memset(a,0,sizeof a);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
scanf("%d%d",&m,&t);
memset(sum,0,sizeof sum);
for (int i=1; i<=n; i++)
sum[i]=sum[i-1]+(ll)a[i];
int p1=p,p2=p;
int tt=t;
while(tt>0)
{
if (p2-(p1)>=m-1) break;
if (p2-(p1)<m-1)
{
if (p2<n) p2++;
if (p1>1) p1--;
if (p1==1 && p2==n) break;
}
tt--;
}
ll ans=sum[p2]-sum[p1-1];
if (tt==0)
{
ans=sum[p2]-sum[p1-1];
}
else
{
if (p2-p1==m) ans=find(p1,p2,tt);
else if (p2-p1==m-1)
{
if (p1>1) ans=max(ans,find(p1-1,p2,tt-1));
if (p2<n) ans=max(ans,find(p1,p2+1,tt-1));
}
}
cout<<ans<<endl;
}
return 0;
}