【题目链接】
ybt 1979: 【18NOIP普及组】龙虎斗
洛谷 P5016 [NOIP2018 普及组] 龙虎斗
【题目考点】
1. long long类型使用
已知变量a, b是int类型的变量,且a * b的值会超出int类型可以表示的范围,如果写为:,c不会得到正确的结果。正确的写法为:long long c = a * b;
long long c = (long long)a * b;
把一个变量强转为long long类型后,后面的运算就是两个long long类型的变量相乘,会得到正确的结果。例:
int a = 100000, b = 100000;
long long c = (long long)a * b;//此时c的值为10^10
2. 求绝对值
<stdlib.h>中有
int abs(int a);
long labs(long a);
但没有针对long long类型变量的求绝对值的函数,所以我们必须手动实现。
long long Abs(long long a)
{
return a > 0 ? a : -a;
}
【解题思路】
-
先把s1个兵添加上去,然后求龙虎双方的气势值。
-
枚举每隔位置,尝试将s2个兵添加到这个位置,求出气势差值。将每次求出的气势差值比较,得到最小的气势差值,以及气势差值最小时,将s2个兵安排的位置。
-
注意:观看数据范围,每个位置的工兵数最大为 1 0 9 10^9 109,共有 1 0 5 10^5 105个位置,加起来的气势和可以估算为 1 0 9 ⋅ 1 0 5 = 1 0 14 10^9 \cdot 10^5 = 10^{14} 109⋅105=1014超出了int型变量可以表达的范围,所以对某些变量要用long long类型
某些int型量间的计算,如s2 * (m - i)
,结果可能超出int型的范围,所以得先强转为long long类型后才能运算
,应写为:(long long)s2 * (m - i)
【题解代码】
解法1:分别求出龙方和虎方的气势
#include<bits/stdc++.h>
using namespace std;
#define N 100005
long long Abs(long long a)
{
return a > 0 ? a : -a;
}
int a[N];//a[i]表示第i位置的工兵数
int main()
{
int n, m, p1, s1, s2, p2;//p2:s2个兵放在p2位置时双方差值最小
long long ql = 0, qh = 0, mn, delta;//ql:龙方气势 qh:虎方气势 mn:两方最小气势差值 delta:气势差值
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i];
cin >> m >> p1 >> s1 >> s2;
a[p1] += s1;//天降神兵
for(int i = 1; i < m; ++i)//统计当前龙方气势
ql += (long long)a[i] * (m - i);
for(int i = m + 1; i <= n; ++i)//统计当前虎方气势
qh += (long long)a[i] * (i - m);
mn = Abs(ql - qh);//双方气势差值最大也就是当前的差值,s2个工兵放下后,气势差值只能更小
p2 = m;//s2个兵放在第m位置时,气势差值即为|ql - qh|
for(int i = 1; i <= n; ++i)
{
if(i < m)
delta = Abs(ql + (long long)s2 * (m - i) - qh);//向龙方i位置放s2个兵,龙方增加气势s2 * (m - i)。求此时龙虎双方的气势差值。
else if(i > m)
delta = Abs(qh + (long long)s2 * (i - m) - ql);//向虎方i位置放s2个兵,虎方增加气势s2 * (i - m)。求此时龙虎双方的气势差值。
if(delta < mn)//求最小的delta,及delta最小时放兵的位置
{
mn = delta;
p2 = i;
}
}
cout << p2;
return 0;
}
解法2:龙方气势是正数,虎方气势是负数
设置变量q表示双方总气势,q > 0表示龙方气势高,q < 0表示虎方气势高, ∣ q ∣ |q| ∣q∣就是双方气势的差值
#include<bits/stdc++.h>
using namespace std;
#define N 100005
long long Abs(long long a)
{
return a > 0 ? a : -a;
}
int a[N];//a[i]表示第i位置的工兵数
int main()
{
int n, m, p1, s1, s2, p2;//p2:s2个兵放在p2位置时双方差值最小
long long q = 0, mn, delta;//q:总气势,q > 0表示龙方气势高,q < 0表示虎方气势高 mn:两方最小气势差值 delta:气势差值
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i];
cin >> m >> p1 >> s1 >> s2;
a[p1] += s1;//天降神兵
for(int i = 1; i <= n; ++i)//统计总气势
q += (long long)a[i] * (m - i);//龙方气势是正数,虎方气势是负数
mn = Abs(q);//双方气势差值最大也就是当前的差值,s2个工兵放下后,气势差值只能更小
p2 = m;//s2个兵放在第m位置时,气势差值即为|q|
for(int i = 1; i <= n; ++i)
{
delta = Abs(q + (long long)s2 * (m - i));//向龙方i位置放s2个兵,总气势改变s2 * (m - i)。
if(delta < mn)//求最小的delta,及delta最小时放兵的位置
{
mn = delta;
p2 = i;
}
}
cout << p2;
return 0;
}