CF1651F Tower Defense 题解

被老师击杀,要写题解一片,如下

upd:感谢laoshan_plus大神帮忙修正latex。

我们注意到 \(2\times10^5\) 是经典的分块数据范围(\(\rm1.5~s\) 完全撑得住)。考虑进行分块,把 \(n\) 个陨石每 \(\sqrt n\) 个一组,那么每一块就会有被击杀了一半(情况 1)、被完全击杀(情况 2)、没有被击杀(即完全存在,情况 3)。

考虑前置时间,因为每个小恐龙移动时间都是 \(1\),对于同一个陨石两个小恐龙相差的时间相同,我们可以认为小恐龙是瞬间移动的。然后分开处理三种情况。

  1. 被击杀了一半,可以直接暴力枚举,易见只会有 \(O(n)\) 段被击杀了一半,复杂度为 \(O(B)\)

  2. 已经被完全击杀,那么会根据时间恢复一部分,考虑不同块恢复时间不一样,我们可以把所有的恢复时间处理出来,排序,处理成 \(kx+b\) 的形式(已知 \(k,b\) 带入 \(x\) 求解答案),然后把答案分成 \(O(B)\) 段,复杂度为 \(O(\log B)\),如果可以完全击杀,那么就直接跳过,如果不可以完全击杀,那么就转入情况 1 进行处理。

  3. 没有被击杀(完全存在),我们考虑把每一段的和记录下来, 如果可以完全击杀,那么全部击杀,标记为被完全击杀,否则转入情况 1 处理,复杂度 \(O(1)\)

我们总共有 \(\frac nB\) 块,复杂度最高在操作 1 和操作 2 的时候实现,为 \(O(nB+\frac{n^2\log B}B)\),注意到在 \(B\) 取到 \(\sqrt{n\log n}\) 的时候最优,但是考虑到常数实现的问题,我取值为 \(O(\sqrt n)\),总体复杂度为 \(O(\sqrt{n\log n})\),实际上完全取不到,而且情况 2 可以通过离线的手法把复杂度降低至 \(O(n\sqrt n)\),但是时间相差不多。(而且这个思路简单。)

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+10;
const int gen=710;
int n,m,c[maxn],r[maxn],h,qi[gen],zh[gen],zg,len,op[gen],jie[gen][gen],k[gen][gen],shu[maxn];
int sumb,b[gen][gen],tp,kuai,sum,ying[gen],ans,t,lst_t,tim[gen],sumc[gen],nn[maxn],val,dy;
struct edge{
	int ll1;
	int ll2;
	int ll3;
}st[gen];
int cmp(edge q,edge w){
	return q.ll2<w.ll2;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>c[i]>>r[i];
		nn[i]=c[i];
	}
	len=sqrt(n);
	for(int L=1,R;L<=n;L=R+1){
		R=min(L+len-1,n);
		zg++;
		qi[zg]=L;
		zh[zg]=R;
		op[zg]=1;
		tp=0;
		sum=0;
		for(int i=L;i<=R;i++){
			shu[i]=zg;
			st[++tp].ll1=r[i];
			st[tp].ll2=c[i]/r[i]+1;
			st[tp].ll3=c[i];
			sum+=r[i];
		}
		sort(st+1,st+1+tp,cmp);
		sumb=0;
		st[tp+1]={-1,-1,-1};
		for(int i=0;i<=tp;i++){
			sum-=st[i].ll1;
			sumb+=st[i].ll3;
			if(st[i].ll2!=st[i+1].ll2){
				ying[zg]++;
				jie[zg][ying[zg]]=st[i].ll2;
				k[zg][ying[zg]]=sum;
				b[zg][ying[zg]]=sumb;
			}
		}
		ying[zg]++;
		jie[zg][ying[zg]]=1e9;
		sumc[zg]=sumb;
	}
	cin>>m;
	while(m--){
		cin>>t>>h;
		for(int i=1;i<=zg;i++){
			tim[i]+=(t-lst_t);
		}
		lst_t=t;
		for(int i=1;i<=zg;i++){
			if(!h){
				break;
			}
			if(op[i]==1){
				if(h>=sumc[i]){
					h-=sumc[i];
					tim[i]=0;
					op[i]=0;
				}
				else{
					op[i]=2;
					tim[i]=0;
					for(int j=qi[i];j<=zh[i];j++){
						if(h>=nn[j]){
							h-=nn[j];
							nn[j]=0;
						}
						else{
							nn[j]-=h;
							h=0;
							break;
						}
					}
					break;
				}
			}
			else if(op[i]==0){
				dy=upper_bound(jie[i]+1,jie[i]+1+ying[i],tim[i])-jie[i]-1;
				val=b[i][dy]+k[i][dy]*tim[i];
				if(h>=val){
					h-=val;
					tim[i]=0;
					op[i]=0;
				}
				else{
					op[i]=2;
					for(int j=qi[i];j<=zh[i];j++){
						nn[j]=min(c[j],r[j]*tim[i]);
					}
					tim[i]=0;
					for(int j=qi[i];j<=zh[i];j++){
						if(h>=nn[j]){
							h-=nn[j];
							nn[j]=0;
						}
						else{
							nn[j]-=h;
							h=0;
							break;
						}
					}
					break;
				}
			}
			else{
				op[i]=0;
				for(int j=qi[i];j<=zh[i];j++){
					nn[j]=min(c[j],nn[j]+r[j]*tim[i]);
				}
				tim[i]=0;
				for(int j=qi[i];j<=zh[i];j++){
					if(h>=nn[j]){
						h-=nn[j];
						nn[j]=0;
					}
					else{
						nn[j]-=h;
						op[i]=2;
						h=0;
						break;
					}
				}
			}
		}
		if(h){
			ans+=h;
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2025-07-12 15:11  特别之处  阅读(30)  评论(0)    收藏  举报