第2题 龙虎斗
一、分析
(1)ci最大值是10亿,n最大值是10万,相乘明显会超过INT_MAX,所以本题要用long long才有可能得满分。若用int,最多只能得80分。
(2)若能想到c是count的缩写,p是position的缩写,s是soldier的缩写,对理解题意会有所帮助。
(3)p1和s1是个很弱的干扰项,直接加到该位置即可。
二、算法实现
求气势差的最小值,有两种方法。
第一种方法是暴力枚举,每移动一次,就判断气势差距是不是变得更小了。这种方法,最多可能要计算10万次。通常几百万内的循环不会运行超时。
方法一 完整代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define LL long long
int main()
{
freopen("fight.in","r",stdin);
freopen("fight.out","w",stdout);
int n, i, m, p1, p2;
cin >> n;
LL c[n + 1], s1, s2;
for(i = 1; i <= n; i++)
{
cin >> c[i];
}
cin >> m >> p1 >> s1 >> s2;
c[p1] += s1;
LL lPower = 0; // 龙势力
for(i = 1; i < m; i++)
{
lPower += c[i] * (m - i);
}
LL rPower = 0;
for(i = m + 1; i <= n; i++)
{
rPower += c[i] * (i - m);
}
//cout << lPower << ' ' << rPower << endl;
LL gap = abs(lPower - rPower); // 双方的气势差
p2 = m; //默认放在m位置
for(i = 1; i <= n; i++)
{
if(i < m) // 神兵加到左侧龙势力
{
if(abs(lPower + s2 * (m - i) - rPower) < gap)
{
gap = abs(lPower + s2 * (m - i) - rPower);
p2 = i;
}
}
else if(i > m) // 神兵加到右侧虎势力
{
if(abs(rPower + (i - m) * s2 - lPower) < gap)
{
gap = abs(rPower + (i - m) * s2 - lPower);
p2 = i;
}
}
}
cout << p2 << endl;
return 0;
}
评测结果:
2.png第二种方法,用龙势力和虎势力的气势差除去s2,会得到s2离m号兵营的距离dist。注意dist不能定义为整数,只能定义为浮点数。当龙势力小于虎势力且距离中包含0.5时,要往左多挪一个位置,这样得到的p2与m的距离最大,从而p2取得最小值 ;当龙势力大于虎势力且距离中包含0.5时,0.5直接去掉,这样就不用往右再挪一个距离了。这样得到的p2与m的距离最小,从而p2取得最小值。
举两个例子,这两个例子里不用考虑p1和s1,对理解题意影响不大。
例1
n = 3,c1 = 10, c3 = 11,c2等于随便一个数,比如1。m = 2。s2 = 2。
在s2没放进去时,势力差gap = 虎势力 - 龙势力 = 1。dist = gap / s2 = 0.5,所以p2 = m – int(dist + 0.5) = 1,即要把s2放到1号营里。
此时龙势力 = 10 + 2 = 12, 虎势力 = 11,gap仍然是1,但此时的p2最小。
例2
n = 3,c1 = 11, c3 = 10,c2等于随便一个数,比如1。m = 2。s2 = 2。
在s2没放进去时,势力差gap = 龙势力 – 虎势力 = 1。dist = gap / s2 = 0.5,所以p2 = m + ceil(dist -0.5) = m + 0 = m,即要把s2放到中立的m号营里。
此时龙势力 = 11, 虎势力 = 10,m号营势力 = 1 + 2 = 3,gap仍然是1,此时的p2最小。
方法二完整代码
#include <iostream>
#include <cmath>
#include<cstdio>
using namespace std;
#define LL long long
int main()
{
freopen("fight21.in","r",stdin);
freopen("fight.out","w",stdout);
int n, i, m, p1, p2;
LL s1, s2;
cin >> n;
LL c[n + 1];
for(i = 1; i <= n; i++)
{
cin >> c[i];
}
cin >> m >> p1 >> s1 >> s2;
c[p1] += s1;
LL lPower = 0; // 龙势力
for(i = 1; i < m; i++)
{
lPower += c[i] * (m - i);
}
LL rPower = 0;
for(i = m + 1; i <= n; i++)
{
rPower += c[i] * (i - m);
}
//cout << lPower << ' ' << rPower << endl;
LL gap = abs(lPower - rPower); // 双方的气势差
p2 = m; // 暂放在m的位置上
float dist = gap * 1.0 / s2; // s2离m兵营的距离
if(rPower > lPower) // 虎势力大,s2要放在龙方
{
//这里floor()也可以改为int()
p2 = m - floor(dist + 0.5);
if(p2 < 1)
{
p2 = 1; // 不能越界
}
}
else if(rPower < lPower)
{
// 注意,这里0.5是要舍弃掉的,大于0.5才加1
p2 = m + ceil(dist - 0.5);
if(p2 > n)
{
p2 = n; // 不能越界
}
}
cout << p2 << endl;
return 0;
}
少儿编程咨询、算法咨询请加微信307591841或QQ群581357582
诺依曼算法公众号.jpg
网友评论