题解:CF1651F Tower Defense

题目传送门

题目大意

给出 \(n\) 个塔,排列在数轴 \(1\sim n\) 的位置上,每个塔有一个魔力值上限 \(c_i\) 和一个恢复速度 \(r_i\),每秒魔力值 \(a_i\) 会变成 \(\min(c_i,a_i+r_i)\) ,每个塔的魔力值初始为 \(c_i\)。之后会有 \(m\) 个怪兽,每一个怪兽会在 \(t_i\) 秒的时候出现在第一个塔面前,之后只要怪兽还有血,就会每秒往后移动一个单位。当怪兽到达塔面前时,塔的魔力值会减少 \(\min(h_i,c_i)\),这时怪兽的血量也会扣除对应值。有些怪兽在经过了 \(n\) 个塔后还有血,要求出这些怪兽的血量和。

解题思路

注意到数据范围,发现 \(O(n\sqrt n)\) 可以过。所以我们考虑分块。

我们对塔进行分块,块的大小为 \(\sqrt n\)。对于一个块,如果怪兽的血量足以支持他走完这一个块,那么说明这个块中的塔就被推平了。对于这种情况,我们可以直接计算,其余情况就要暴力计算。

现在考虑怎么预处理出每个块在经过 \(i\) 的时间后的恢复血量。这个我们先考虑单个塔是怎么回血的。每个塔如果可以恢复 \(r_i\) 的血量那就恢复 \(r_i\),否则就恢复 \(c_i\bmod r_i\)

所以我们可以先对每个块增加 \(r_i\) 的那一段进行差分,再做一次前缀和。之后在对恢复 \(c_i\bmod r_i\) 的那一段做一次前缀和。

之后如果怪物血量大于等于块的血量,就直接对块进行操作,否则就暴力计算。

代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3010101;
ll n,m,tot,a[N],c[N],h[N],r[N],L[N],R[N],vis,t[N],f[N],ans;
void js(ll x,ll y,ll s,ll t){
    vis=0;
    for(int i=L[x];i<=R[x];i++){
        a[i]=min(c[i],a[i]+(s-t)*r[i]);
        if(a[i]<=h[y]){
            h[y]-=a[i];
            a[i]=0;
        }
        else{
            a[i]-=h[y];
            h[y]=0,vis=1;
        }
    }
}
void solve(ll x){
    vis=1;
    ll ti=0;
    for(int i=0;i<=5e5;i++)f[i]=0;
    for(int i=L[x];i<=R[x];i++){
        f[1]+=r[i];
        f[c[i]/r[i]+1]-=r[i];
    }
    for(int i=1;i<=5e5;i++)f[i]+=f[i-1];
    for(int i=L[x];i<=R[x];i++)f[c[i]/r[i]+1]+=c[i]%r[i];
    for(int i=1;i<=5e5;i++)f[i]+=f[i-1];
    for(int i=1;i<=m;i++){
        if(!h[i])continue;
        ll now=L[x]+t[i]-1;
        if(vis)js(x,i,now,ti);
        else{
            if(h[i]<f[now-ti])js(x,i,now,ti);
            else h[i]-=min(f[now-ti],h[i]);
        }
        ti=now;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    tot=sqrt(n)+1;
    for(int i=1;i<=n;i++)cin>>c[i]>>r[i],a[i]=c[i];
    for(int i=1;i<=tot;i++){
        L[i]=R[i-1]+1;
        R[i]=min(n,i*tot);
    }
    cin>>m;
    for(int i=1;i<=m;i++)cin>>t[i]>>h[i];
    for(int i=1;i<=tot;i++)solve(i);
    for(int i=1;i<=m;i++)ans+=h[i];
    cout<<ans;
    return 0;
}
posted @ 2025-09-07 21:40  一班的hoko  阅读(16)  评论(0)    收藏  举报