P8777 [蓝桥杯 2022 省 A] 扫描游戏 题解
bianshiyang · · 题解
题目传送门
题目简意
输出被顺时针旋转的棒碰到的排名顺序。
分析
首先我们需要知道棒被碰到的顺序与什么有关,显然,和该点与原点连线与
那么如何判断两个点的排名是否相同呢?当且仅当这两个点所对应的
几点注意事项:
一、数据量很大建议使用 long long 或者 double 存储。
二、对于每一个不同的
三、因为遍历的是两个周期的 我才不会告诉你我是因为这个卡了十几次 )。
最终程序时间复杂度为
本代码还跑到了全洛谷最优解哈哈哈。
Record
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int n,tot,ans[N],ttt;//tot表示遍历到的顺序(即不包括重复的),ttt表示排名(即包括重复的),两者有一定的差异,请读者在后面的代码自行体会
int cnt1,cnt2;
double l,x,y,z;
unordered_map<double,bool> vis;//记录每个theta是否被访问过
bool ok;
struct node{
int id;
double rad,r,z;
};//id表示这个点的编号,r即为d,rad即为tan theta,z同题目
bool cmp(node x,node y)
{
if(x.rad==y.rad) return x.r<y.r;
return x.rad>y.rad;
}//排序时关键词一定要看好
node zheng[N],fu[N];//分成两个半圆
signed main()
{
memset(ans,-1,sizeof(ans));
scanf("%d%lf",&n,&l);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&x,&y,&z);
if(x==0&&y==0)
{
ans[i]=1;
l+=z;
tot++;
}//对于在原点的点特判
if(x==0)//特判y轴
{
if(y>0)
{
zheng[++cnt1].id=i;
zheng[cnt1].r=(double)sqrt(x*x+y*y);
zheng[cnt1].rad=1e20;//赋为无穷大
zheng[cnt1].z=(double)z;
}
else
{
fu[++cnt2].id=i;
fu[cnt2].r=(double)sqrt(x*x+y*y);
fu[cnt2].rad=1e20;
fu[cnt2].z=(double)z;
}
}
else if(x>0)
{
zheng[++cnt1].id=i;
zheng[cnt1].r=(double)sqrt(x*x+y*y);
zheng[cnt1].rad=(double)y/x;
zheng[cnt1].z=(double)z;
}
else
{
fu[++cnt2].id=i;
fu[cnt2].r=(double)sqrt(x*x+y*y);
fu[cnt2].rad=(double)y/x;
fu[cnt2].z=(double)z;
}
}
sort(zheng+1,zheng+cnt1+1,cmp);
sort(fu+1,fu+cnt2+1,cmp);
while(1)//模拟转圈过程
{
ok=0;
vis.clear();
for(int i=1;i<=cnt1;i++)
{
if(ans[zheng[i].id]!=-1) continue;//已经遍历过
if(l<zheng[i].r) continue;//扫不到
if(!vis[zheng[i].rad])
{
vis[zheng[i].rad]=1;
ttt=tot+1;//新的theta才更新排名
}
ans[zheng[i].id]=ttt;
l+=zheng[i].z;
tot++;
ok=1;
}
vis.clear();//这个真的真的真的真的很重要!!!
for(int i=1;i<=cnt2;i++)//同上
{
if(ans[fu[i].id]!=-1) continue;
if(l<fu[i].r) continue;
if(!vis[fu[i].rad])
{
vis[fu[i].rad]=1;
ttt=tot+1;
}
ans[fu[i].id]=ttt;
l+=fu[i].z;
tot++;
ok=1;
}
if(ok==0) break;//没有任何点被修改则跳出循环
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}
一件有趣的事:之前不小心把其中的一个 数据水啦!