AtCoder Beginner Contest 153 F - Silver Fox vs Monster


題目鏈接 https://atcoder.jp/contests/abc153/tasks/abc153_f

題意 : 在坐標軸上有一些怪獸,每個怪獸有對應的生命值hi,你可以對他們進行炮擊,你的每次炮擊可以隊該點前后D范圍內的怪獸造成A的傷害,問最少要炮擊多少次。

我的最初的想法是先排序,掃到最左邊的怪獸,先進行炮擊,把他打死,然后記錄炮擊了多少次,然后把其后2d距離的怪獸都炮擊一下發現超時

代碼如下:

inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
const int N = 2e5+5;
struct mon
{
        ll x,h;
};
mon monster[N];
bool cmp(mon a, mon b)
{
    return a.x < b.x;
}
int main()
{
    //ios::sync_with_stdio(false);cin.tie(NULL);
    ll n, d, a;
    n = read();
    d = read();
    a = read();
    for (int i = 0; i < n; i++)
    {
        monster[i].x = read();
        monster[i].h= read();
    }
    sort(monster, monster + n,cmp);
    ll ans = 0;
    for (int i = 0; i < n; i++)
    {
        if (monster[i].h>0)
        {
            ll xx = monster[i].x + d;
            ll num = (monster[i].h + a - 1) / a;
            ans += num;
            monster[i].h = 0;
            bool flag = false;
            for (int j = i + 1; monster[j].x >= (xx - d) && monster[j].x<= xx + d && j < n;j++)
            {
                monster[j].h-=a*num;

            }
        }
    }
    cout << ans << endl;

}

后來學習了大佬的代碼,他是這么操作的,建立一個數組c[i],記錄每個點已經炮擊了幾次,已經被炮擊的次數我們用need來表示,那么i那個位置炮擊的次數就是:c[i] += need, 下一個點 i + 1 已經炮擊的次數就是c[i + 1] += c[i],因為炮擊的范圍是炮擊點左右距離D,范圍外就無效,所以每個點i你要先找到他最遠能打到哪里,然后要事先減掉need,即c[j] -= need; 這樣,當i到了j-1時,執行c[i+1] += c[i], need正好抵消,我覺得這個技巧太妙了

代碼里面有一個技巧可能有點難理解

(monster[i].h - c[i]*a + a - 1)/a 這句話相當於

ll hh = monster[i].h - c[i]*a
if (hh % a > 0)
  need = hh/a + 1
else if (hh %a ==0)
  need = hh/a

代碼:

#include<iostream>
#include<string>
#include <cstdlib>
#include <algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include <iomanip>

// #pragma comment(linker, "/STACK:1024000000,1024000000")
// #define pi acos(-1)
// #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x7f7f7f7f //2139062143
#define INF1 0x3f3f3f3f //1061109567
#define INF2 2147483647
#define llINF 9223372036854775807
#define pi 3.141592653589793//23846264338327950254
#define pb push_back
#define ll long long
#define debug cout << "debug\n";
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(false);cin.tie(NULL);
#define scai(x) scanf("%d", &x)
#define sca2i(x, y) scanf("%d %d", &x, &y)
#define scaf(x) scanf("%lf", &x)
#define sca2f(x, y) scanf("%lf %lf", &x, &y)
#define For(m,n) for (int i = m;  i < n; i++)

#define local
#ifdef local
#endif

#define MAX 10233
#define LCH(i) ((i) << 1)
#define RCH(i) ((i) << 1 | 1)
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
const int N = 2e5+5;
ll c[N];
struct mon
{
        ll x,h;
};
mon monster[N];
bool cmp(mon a, mon b)
{
    return a.x < b.x;
}
int main()
{
    //ios::sync_with_stdio(false);cin.tie(NULL);
   // cout << 50ll << endl;
    ll n, d, a;
// 這里是快讀 n
= read(); d = read(); a = read(); for (int i = 0; i < n; i++) { monster[i].x = read(); monster[i].h= read(); }
// 對怪事的位置進行排序 sort(monster, monster
+ n,cmp); ll ans = 0; for (int i = 0,j = 0; i < n; i++) { while(j < n && monster[j].x <=monster[i].x + 2*d) // 找到這次炮擊能打到的最遠的怪獸 ++j; ll need = max((monster[i].h - c[i]*a + a - 1)/a, 0ll); //這個怪獸需要炮擊的次數就是怪獸的生命值h減去之前炮擊的次數c[i]*a,0ll的意思是longlong 的0; ans += need; c[i] += need; c[j] -= need; 把炮擊范圍外的第一個怪獸先剪掉need c[i+1] += c[i]; } cout << ans << endl; }

 學了差分,發現大佬的代碼其實就是差分的思想。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM