线上OJ:
一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1979 (opens in a new tab)
洛谷:https://www.luogu.com.cn/problem/P5016 (opens in a new tab)
AcWing:https://www.acwing.com/problem/content/476/ (opens in a new tab)
核心思想:
- 题中提到
对于 100% 的数据,n可到 10^5, s1,s2可到 10^9
。 所以气势值会达到 ,所以本题需使用 long long - 输入的 s1 先加到 p1 位置上去,后面就不用再处理了
- 分别计算左侧的气势 ql 和右侧的气势 qr(ql 和 qr 的差值记为 d)
a. 如果 ql > qr,则说明 p2 放在右侧
b. 如果 ql < qr,则说明 p2 放在左侧
c. 如果 ql == qr,则说明 p2 放在 m 处即可 - 在计算具体位置时,可按如下思路考虑
a. 若 ql 和 qr 的差值为 11,那肯定是把这11个差值都弥补完是最好的。假如此时 s2 为4个工兵,则平均到每个工兵的距离差值为11÷4=2.75。由于题中距离为整数,所以比较 2.75 附近的两个整数(2和3),看哪个更接近 11。如果选择3,因为 3*4=12,12-11=1。如果选择2,则 2*4 = 8,11-8=3。所以选择 3 比选择2更好。
b. 若 ql 和 qr 的差值为 13,那肯定是把这13个差值都弥补完是最好的。假如此时 s2为4个工兵,则平均到每个工兵的距离差值为13÷4=3.25。由于题中距离为整数,所以比较 3.25 附近的两个整数(3和4),看哪个更接近 13。如果选择3,因为 3*4=12,13-12=1。如果选择4,则 4*4 = 16,16-13=3。所以选择 3 比选择4更好。
所以我们只要记 ,(此时 k 为整数位),然后比较 和 哪个更接近 d 即可。 - 在算出 p2 时,要判断是否越界 。
如果 p2 是在 m 的右侧,则最大不能超过 n。如果 p2 在m的左侧,则最小不能低于 1
题解代码:
#include <bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
// 由于对于 100% 的数据,n可到 10^5, s1,s2可到 10^9。 所以气势值会达到 10^5 * 10^9 即 10^14,所以使用long long
int main()
{
ll n, m, p1, p2, s1, s2;// p2 即为所求
ll ql = 0, qr = 0, d; // ql:左侧的龙方气势 qr:右侧的虎方气势 d:气势差
cin >> n;
ll a[n+5]; // a[i]表示第i位置的工兵数
for(int i = 1; i <= n; ++i) cin >> a[i]; // 读入每个位置的工兵数
cin >> m >> p1 >> s1 >> s2;
a[p1] += s1; // 把 s1 先加到 p1 位置的工兵数上去
// 统计当前左侧龙方气势
for(int i = 1; i < m; ++i) ql += a[i] * (m - i);
// 统计当前右侧虎方气势
for(int i = m + 1; i <= n; ++i) qr += a[i] * (i - m);
if(ql > qr)
{
d = ql - qr;
int k = d / s2;
if( (d - k * s2) <= ((k + 1) * s2 - d) )
p2 = m + k;
else
p2 = m + k + 1;
if(p2 > n) p2 = n;
}
else if(ql < qr)
{
d = qr - ql;
int k = d / s2;
if( (d - k * s2) <= ( (k + 1) * s2 - d ) )
p2 = m - k;
else
p2 = m - (k + 1);
if(p2 < 1) p2 = 1;
}
else if(ql == qr) // 如果本来气势就相等,则直接放在 m 处即可(即两边都不加)
{
p2 = m;
}
cout << p2;
return 0;
}