P5016 [NOIP2018 普及组] 龙虎斗
写在前面
嗯好像是第一个写在前面欸,那就浅浅的介绍一下本人吧
XXX 一名OIER 喜欢水题打摆
反正实力不咋地
文章中的错误视作者精神情况而定,多多嘲讽包含
题目介绍
https://www.luogu.com.cn/problem/P5016
题目链接扔过去了,需要自取
代码思路
根据题目描述,我们需要选择一个兵营编号 \(p_2\),将手中的 \(s_2\) 位工兵派往该兵营,使得龙虎双方的气势差距尽可能小。
首先,我们可以计算当前龙方和虎方的气势差距。
设兵营 \(i\) 到兵营 \(m\) 的距离为 \(d_i = |i - m|\),则兵营 \(i\) 的气势为 \(c_i \times d_i\)。
龙方的气势为 \(\text{dragon} = \sum\limits_{i=1}^{m-1}(c_i \times d_i)\),虎方的气势为 \(\text{tiger} = \sum\limits_{i=m+1}^{n}(c_i \times d_i)\)。
如果手中的工兵派往某个兵营 \(i\)(\(1 \leq i \leq n\)),那么龙方的气势变为 \(\text{new_dragon} = \text{dragon} + s_2 \times (d_i - d_m)\)。
根据题目要求,我们需要选择一个兵营 \(p_2\),使得 \(\text{new_dragon}\) 与 \(\text{tiger}\) 的差值尽可能小。
换言之,我们要选择一个兵营 \(_2\),使得 \(\text{abs(new_dragon - tiger)}\) 最小。
代码实现
#include <bits/stdc++.h>
using namespace std;
long long a[1000000],n,p,k,s,ans=0,sum=0,m;
int main() {
// freopen("fight.in","r",stdin);
// freopen("fight.out","w",stdout);
scanf("%lld",&n);
for(int i = 1; i <= n; i++)scanf("%lld",&a[i]);
scanf("%lld%lld%lld%lld",&m,&p,&s,&k);
for(int i = 1; i <= n; i++) sum += a[i] * (m - i);
sum += s * (m - p);
ans = m + int(sum * 1.0 / k + 0.5 * (sum > 0 ? 1 : -1));
if(ans > n)ans = n;
else if(ans < 1)ans = 1;
printf("%lld",ans);
// fclose(stdin);
// fclose(stdout);
return 0;
}
首先,我们读入兵营数量、每个兵营的工兵数量,分界兵营编号,突然出现工兵的兵营编号,以及手上的工兵数量。
然后,我们需要计算龙方的气势。根据题目描述,龙方的气势是将靠左的兵营中的工兵数量与距离分别相乘后的累加和。具体地,我们使用一个变量 sum
来保存这个累加和。我们可以遍历靠左的兵营,累加每个兵营的工兵数量乘以距离。
接下来,我们需要考虑突然出现的工兵。根据题目描述,突然出现的工兵会进入一个兵营,我们需要计算新的龙方的气势。为了简化计算,我们可以将这些突然出现的工兵直接加到原来的 sum
中。具体地,我们可以把突然出现的工兵数量乘以分界兵营到突出现兵营之间的距离,并将其加到 sum
中。
现在,我们已经得到了新的龙方的气势。接下来,我们需要根据手上的工兵数量,计算选择的兵营编号。根据题目描述,我们需要找到一个兵营,使得龙方的气势与虎方的气势之间的差值最小。为了尽可能使差值最小,我们可以将 sum
除以手上的工兵数量 k
,这样我们就得到了 sum / k
,即平均每个工兵能贡献的气势值。然后,我们可以将这个平均值加到分界兵营的编号上,得到最终选择的兵营编号。
我们需要注意处理边界情况。如果计算得到的兵营编号超过了兵营的范围,我们需要将其修正到合法的范围内。
最后,我们输出结果。
这段代码的思路是通过累加和的方式计算龙方的气势,然后根据手上的工兵数量,计算选择的兵营编号。这种方法比较简洁有效,可以在较短的时间内求解出结果。
写在后面
这道题是考试时唯一A掉的题,所以写这篇题解也是为了纪念一下这个巨大的进步
作者写这篇题解的时候精神状态濒临崩溃,反正错误巨多,bxwp
接下来的这几天会快乐打摆,所以……
作者鸽掉了!快来嘲讽ta!
当然,欢迎提问,我会尽我所能回答滴
写博客不易,拜托把下面的推荐点一下呗~