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; }