题解链接:题解链接

RD是输入,OT是输出

A – SERVAL VS MONSTER
链接:
A题

题意:
给你怪物血量H和攻击一次扣A血,问至少要攻击几次能使怪物的血量小于或者等于0

解法:
按题意模拟,考虑到循环减去时间会较长,故判断奇偶后除求解攻击次数

代码

int main(){
    LL h, a;
    RD(h, a);
    if (h%a == 0) cout << h/a << '\n';
    else  cout << h/a+1 << '\n';
}

B – COMMON RACCOON VS MONSTER
链接:
B题

题意:
怪物有H滴血,有N种攻击方式,每种攻击方式能造成ai的伤害,问每种攻击方式攻击一次是否能够使怪物血量小于或者等于0

解法:
模拟,直接扣最后判断即可

代码:

int main(){
    int h, n; RD(h, n);
    for(int i = 0; i < n; i++){
        LL x; RD(x);
        h-=x;
    }
    if (h <= 0) OT("Yes\n");
    else OT("No\n");
}

C – FENNEC VS MONSTER
链接:
c题

题意:
Fennec 和 N 个怪物进行战斗,第 i 个怪物的血量为 Hi ,Fennec可以进行两种操作,一种攻击扣一滴血,另一种特殊攻击,能够使一个怪物的血量降到0,但是特殊攻击只能进行K次,求需要进行几次攻击

解法:
删去K个H大的怪物,剩余的平a

代码:

const int N = 2e5+50;
int H[N];
int main(){
    LL n, k; RD(n, k);
    REP(i, n) RD(H[i]);
    sort(H, H+n);
    LL ans = 0;
    for(int i = 0; i < n-k; i++){
        ans += H[i];
    }
    OT(ans);
}

D – CARACAL VS MONSTER
链接:
D题

题意:

怪物有H滴血,有两种操作方式,问需要操作几次?
如果 H > 1进行分裂和扣半血操作(扣半血是下取整操作)【这是算一次操作】
如果 H <= 1直接血量降为 0

解法:
仔细看样例会知道这是一题数学题,多列样例猜测规律
血量H 操作次数ans

1 1
2 3
3 3
4 7

1000000000000 1099511627775
画出图来后知道在大于1的时候一定要经过分裂,直到分裂扣血到1停止

int main(){
    LL h; RD(h);
    LL ans = 0, x = 1;
    while(x <= h){ans+=x;x<<=1;}
    OT(ans);
}

E – CRESTED IBIS VS MONSTER
类型:
完全背包问题、动态规划

链接:
E题

题意:
怪物有H滴血,魔法师有N个技能,每进行i技能时,魔法师自身消耗b[ i ]法力值,怪物扣血a[ i ],求使怪物血量小于等于0,最少消耗的法力值

解法:
H滴血相当于背包容量,N个技能相当于N种选择,a[ i ] 相当于物品重量, b[ i ]相当于每个物品的价值
转移方程

int x = max(0, j-a[i]);
dp[j] = min(dp[j],dp[x]+b[i]);

即选择下一个技能的话就要加上下一个技能的b[ i ],不选择的话就不加

代码:

const int maxn = 1e5+10;
int a[maxn], b[maxn];
const int N = 1e4+10;
int dp[N]= {0};
int main(){
    int h, n; RD(h, n);
    for(int i = 1; i <= n; i++){
        RD(a[i], b[i]);
    }
    FOR_1(i, 1, h) dp[i] = 1e9; dp[0] = 0;
    FOR_1(i, 1, n){
        FOR_1(j, 0, h){
            int x = max(0, j-a[i]);
            dp[j] = min(dp[j],dp[x]+b[i]);
        }
    }
    OT(dp[h]);
}

F – SILVER FOX VS MONSTER
链接:
F题

题意:
银狐和N个怪物战斗。N个怪物在一条线上,第i个怪物站在第xi个位置,并且具有hi点血量,现在进行激光炮对x位置进行轰击,会对x-D 到 x+D范围内怪物造成伤害,求解轰击次数。

解法:
建立一个c[ i ]计算每个点位的炮击次数need,即c[ i ]+=need,计算最远的炮击位置c[i+1] += c[i],超出范围的都会扣除need,所以+c[i]-need就会抵消了

代码:

const int N = 2e5+50;
LL c[N];
struct mos{
    int x;
    int h;
} p[N];
bool cmp(mos a, mos b){
    return a.x < b.x;
}
int main(){
    int n, a, d; RD(n, d, a);
    FOR_1(i, 1, n){
        RD(p[i].x, p[i].h);
    }
    sort(p+1, p+n+1, cmp);
    LL ans = 0;
    for (int i = 1,j = 1; i <= n; i++)
    {
        while(j <= n && p[j].x <= p[i].x + 2*d)
            ++j;
        LL need = max((p[i].h - c[i]*a + a - 1)/a, 0ll);
        ans += need;
        c[i] += need;
        c[j] -= need;
        c[i+1] += c[i];
    }
    cout << ans << endl;
}