题解:P12951 [GCJ Farewell Round #2] Collecting Pancakes
OIer_sundingjia · · 题解
闲话
造福一下被要被分类讨论吃掉的后人。
我不明白:这题时限为什么要给到
切入正题
问题 1
我们先考虑这样一件事:如果两人选择的第一叠煎饼已知的话。Alice 能拿多少煎饼?
举个例子:
注:以上图片建议拖到新窗口打开。下同。
由于每次只能拿到相邻的。所以 Bob 不能跨过 Alice 拿的第一叠煎饼,拿到 Alice 第一叠煎饼左侧的煎饼。
也就是说,Alice 选的第一叠煎饼与端点之间的煎饼,是 Alice 无论何时拿都能拿到的,所以我们可以最后去拿。
Bob 同理。
示意图:
现在唯一存在争议的地方是中间的几叠煎饼。
显然,Alice 和 Bob 一直往中间拿是更优的。
中间两人将会在两个人所选第一叠煎饼之间这个区间的中点相遇。
最终局面如下图。
问题 2
如果只知道 Alice 第一叠选的哪?这时候 Bob 应在哪选第一叠能使得 Alice 拿到的煎饼最少?Alice 最少拿多少?
根据前面的分析,一下策略是最有优的:
-
紧贴着 Alice 选的第一叠(如果可以的话)。
如果你不贴着的话,两叠之间的煎饼就有一半要拱手让人,对于 Bob 显然不优。
-
选择
L_b 或R_b 。理由同上。
第二问则可以将
做法
枚举 Alice 选哪,之后你就得到了问题
按照问题
暴力求和为
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
long long a[N],sum[N];
int la,lb,ra,rb;
int n;
long long ans;
int cnt;
void solve()
{
cnt++;
cin>>n;ans=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; //前缀和
cin>>la>>ra>>lb>>rb;
for(int i=la;i<=ra;i++)
{
//枚举Alice第一叠煎饼位置
long long p=0x3f3f3f3f3f3f3f3f; // 选这最少能拿多少煎饼(采取最优策略)
if(lb<=i-1&&rb>=i-1) p=min(p,sum[n]-sum[i-1]);
if(lb<=i+1&&rb>=i+1) p=min(p,sum[i]); // 紧贴着
if(lb>i+1)
{
int mid=(lb+i)/2;
p=min(p,sum[mid]);
}
if(rb<i-1)
{
int mid=(rb+i-1)/2;
p=min(p,sum[n]-sum[mid]);
} // 选Lb或Rb
ans=max(ans,p);
}
cout<<"Case #"<<cnt<<": "<<ans<<'\n';
}
int T;
signed main()
{
cin>>T;
while(T--) solve();
return 0;
}