CH#46 磁力块 分块

时间:2023-03-10 02:02:10
CH#46 磁力块 分块

正解:分块+bfs

解题报告:

先放个传送门,然后瞎扯淡下QAQ

突然感觉不停课大概是正确的选择QAQ

大概实在是没有天赋?明明都知道正解是分块甚至还听了下解法感觉理解了,再看一次依然没想到解法,,,好菜啊,,,所以这种明明都落实过然而再看一次还是做不出来的题目是最最应该写题解的了QAQ

昂不叨叨了说说这题正解

1)  显然的是每块石头能吸的磁石是固定的,不存在改变次序之后会有改变,所以直接拿得到哪个磁石就把这个磁石能吸到的磁石都加入   队列,bfs就好了

这里是个最简单的暴力想法?还是不难想的我觉得qwq

还一个很显然的是这个暴力会超时,于是怎么优化呢?

当当!分块!好了说完了没了

2) ummm我第二次看到这题的时候就卡在这儿了QAQ不知道怎么分块QAQ

这时候重新梳理下这题,冷静思考一下这题,发现如果磁石被吸引要有俩条件

第一个是质量<=磁力;第二个是距离<=半径

根据分块的常见思路来说显然就是根据一个分块根据另一个在分块内部再排序是趴

那就以按质量分块为例说下大致思路(阿西其实是书中讲的按质量分块我也不清楚能不能按距离?大胆猜测一波也许可以趴QAQ打算有时间去打下按距离分块的看看可不可以qwq

那按照常见套路来说就是按质量分块然后再在内部按照距离分块

这样的话对每个磁石都是只有前面一些块能吸上(满足质量qwq

然后每个块的内部又是只有前面一些块能吸上(满足距离qwq

然后就朴素扫描一波就欧克了

嗷这么简单的优化当然是不够的

还有一个小tips是说,每个块内部能被吸走的磁石一定是连续的(显然qwq

所以可以记录下每块内部最后一个被吸走的磁石的位置,这样每个块内部每次算的时候直接从第一个没被吸走的磁石开始枚举就好了

太难受辽,对了几个数据错了几个

唯一安慰的就是CH可以随便下数据QAQ太美好辽QAQ

然后先存下代码,晚上打完QAQ

之前思考完之后就打代码嘛,然后出现了好几个错误,这里记录一下QAQ

第一个是符号打错辽?就<打成>了然后居然过了样例,,,太水了点儿这个也,,,

第二个是距离要用double,其实我开始想了一下?然后不知道哪来的自信觉得,不要开double耶,,,然后调了贼久,,,烦躁,大概才是原罪趴:D

第三个是没开ll,依然是距离那儿,改了半天发现出现了-nan?于是就猜出来估计是要ll

第四个是全开ll会超时,然后其实只要距离那儿开ll就行了

over:D

然后放个代码就,完美结束辽?

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rp(i,x,y) for(register int i=x;i<=y;++i)
#define my(i,x,y) for(register int i=y;i>=x;--i) const int N=+,sqtN=+;
int x,y,pl,rl,n,len,mx[sqtN],fr[sqtN],bl[N],to[sqtN],ans;
bool vis[N];
queue<int>Q; inline int read()
{
register char ch=getchar();register int x=;register bool y=;
while(ch!='-' && (ch<'' || ch>''))ch=getchar();
if(ch=='-')ch=getchar(),y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=getchar();
return y?x:-x;
} struct node
{
int m,p,r,bl;double jl;
inline void rd(){int xx=read(),yy=read();jl=(double)sqrt((ll)(x-xx)*(x-xx)+(ll)(y-yy)*(y-yy));m=read();p=read();r=read();}
}st[N]; inline bool cmp1(node gold,node genius){return gold.m<genius.m;}
inline bool cmp2(node gold,node genius){return gold.bl==genius.bl?gold.jl<genius.jl:gold.bl<genius.bl;}
inline void pre()
{
x=read();y=read();st[].p=pl=read();st[].r=rl=read();n=read();len=sqrt(n);
rp(i,,n)st[i].rd();sort(st+,st++n,cmp1);
rp(i,,n)st[i].bl=(i-)/len+;
rp(i,,(n-)/len+)fr[i]=(i-)*len+,to[i]=min(n,i*len),mx[i]=st[to[i]].m;
sort(st+,st++n,cmp2);
}
inline void work()
{
Q.push();
while(!Q.empty())
{
int now=Q.front();Q.pop();
rp(i,,(n-)/len+)
{
if(mx[i]>st[now].p)
{
rp(j,fr[i],to[i])if(st[j].jl<st[now].r && st[j].m<=st[now].p && !vis[j])vis[j]=,Q.push(j),++ans;
break;
}
rp(j,fr[i],to[i]){if(st[j].jl>st[now].r)break;if(!vis[j])vis[j]=,Q.push(j),++ans;++fr[i];}
}
}
printf("%d\n",ans);
} int main(){pre();work();}

这儿!是!代码!qwq!

啊不对之前提出了俩问题依然没有得到解决,但是我现在这么菜的实力大概还是搞不出来的,等以后做的题目比较多了再来总结,也许会总结到分块学习笔记中?

重申一下问题是啥哦qwq

就,为什么这题看到之后会想到用分块以及这个题目的时间复杂度(好像说分摊下来是O(n)?然而不会证明:D真好:D

好滴强行当做搞完了溜了qwq