AtCoder ABC153F - Silver Fox vs Monster(思维 + 二分 + 差分)

题目链接:https://atcoder.jp/contests/abc153/tasks/abc153_f

题意:有n个怪兽站在一维数轴上的n个位置,每个怪兽都有自己的血量。你每次可以对[pos - D,pos+D]的所有怪兽的血量减A,问你最少需要使用多少次可以使的所有的怪兽的血量小于等于0.

思路:刚看题意时是一点思路都没有的。。。后来在网上找了好多题解才看懂。这一题确实设计的挺巧妙的,不看题解,我怎么也想不到这一题会用差分来做!!!我们可以用一个差分数组来记录某个位置一共进行了多少次攻击。我们将输入数据按照位置从小到大排序。之后遍历整个数组。每到一个位置,q[i] += q[i-1],这就是这个位置受先前的影响,我们让这个位置的怪兽的血量val减去q[i] * A,如果此时val小于等于0,那这个位置的怪就挂了,我们就不需要管啦。否则,ans += (val + x - 1) / x,之后我们要找到[pos,pos + 2 * D]范围内最远的输入的最远的位置res,q[res] -= (val + x - 1) / x。怎么找呢?直接for循环肯定不行,所以一个简单的二分来找。这题,就结束啦。

AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 2e5 + 7;
const int INF = 0x3f3f3f3f;

struct node {
    int pos,val;
}a[maxn];

bool cmp(node aa,node bb) {
    return aa.pos < bb.pos;
}

LL q[maxn];

int main() {
    int n,d,x;
    scanf("%d%d%d",&n,&d,&x);
    for(int i = 1 ; i <= n ; i++) {
        scanf("%d%d",&a[i].pos,&a[i].val);
    }
    d <<= 1;
    sort(a+1,a+n+1,cmp);
    LL ans = 0;
    for(int i = 1 ; i <= n ; i++) {
        q[i] += q[i-1];
        a[i].val -= q[i] * x;
        if(a[i].val <= 0) continue;
        LL temp = (a[i].val + x - 1) / x;
        ans += temp;
//        cout << "i = " << i << " ans = " << ans << endl;
        q[i] += temp;
        int l = i , r = n;
        int res = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
//            cout << "l = " << l << " r = " << r << " " << a[mid].pos << " " << a[i].pos + d << endl;
            if(a[mid].pos <= a[i].pos + d) {
                res = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
//        cout << "res = " << res << endl;
        q[res+1] -= temp;
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(差分,思维,二分)