2018NOIP普及组真题 2. 龙虎斗

线上OJ:

一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1979

核心思想:
  1. 题中提到 对于 100% 的数据,n可到 10^5, s1,s2可到 10^9。 所以气势值会达到 1 0 5 ∗ 1 0 9 = 1 0 14 10^5 * 10^9 = 10^{14} 105109=1014,所以本题需使用 long long
  2. 输入的 s1 先加到 p1 位置上去,后面就不用再处理了
  3. 分别计算左侧的气势 ql右侧的气势 qr(ql 和 qr 的差值记为 d)
    a. 如果 ql > qr,则说明 p2 放在右侧
    b. 如果 ql < qr,则说明 p2 放在左侧
    c. 如果 ql == qr,则说明 p2 放在 m 处即可
  4. 在计算具体位置时,可按如下思路考虑
    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 / s 2 k = d / s2 k=d/s2,(此时 k 为整数位),然后比较 k ∗ s 2 k*s2 ks2 ( k + 1 ) ∗ s 2 (k+1)*s2 (k+1)s2 哪个更接近 d 即可。
  5. 在算出 p2 时,要判断是否越界 [ 1 , n ] [1, n] [1,n]如果 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值