CF1651F Tower Defense 题解
被老师击杀,要写题解一片,如下
upd:感谢laoshan_plus大神帮忙修正latex。
我们注意到 \(2\times10^5\) 是经典的分块数据范围(\(\rm1.5~s\) 完全撑得住)。考虑进行分块,把 \(n\) 个陨石每 \(\sqrt n\) 个一组,那么每一块就会有被击杀了一半(情况 1)、被完全击杀(情况 2)、没有被击杀(即完全存在,情况 3)。
考虑前置时间,因为每个小恐龙移动时间都是 \(1\),对于同一个陨石两个小恐龙相差的时间相同,我们可以认为小恐龙是瞬间移动的。然后分开处理三种情况。
-
被击杀了一半,可以直接暴力枚举,易见只会有 \(O(n)\) 段被击杀了一半,复杂度为 \(O(B)\)。
-
已经被完全击杀,那么会根据时间恢复一部分,考虑不同块恢复时间不一样,我们可以把所有的恢复时间处理出来,排序,处理成 \(kx+b\) 的形式(已知 \(k,b\) 带入 \(x\) 求解答案),然后把答案分成 \(O(B)\) 段,复杂度为 \(O(\log B)\),如果可以完全击杀,那么就直接跳过,如果不可以完全击杀,那么就转入情况 1 进行处理。
-
没有被击杀(完全存在),我们考虑把每一段的和记录下来, 如果可以完全击杀,那么全部击杀,标记为被完全击杀,否则转入情况 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;
}
浙公网安备 33010602011771号