牛客练习赛48 D 小w的基站网络
链接:https://ac.nowcoder.com/acm/contest/923/D
来源:牛客网
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
示例2
示例3
备注:
由于输入量和输出量比较大,请勿使用cin,cout进行输入输出。
本题不会卡常数,不用特地使用输入输出挂。
思路:
题意:
t=|x1*y2-x2*y1|;
输出基本点(第k个点)到其他各点最小的t值,因为基本点可以途经其他点最后到达目标点,如果无法到达目标点那么输出-1,自己到达自己则输出0,否则输出t值
步骤:
1.讲点按照与x正方向轴的夹角(点都在x轴的上半部分,点的y值均大于0)由小到大排个序(操作就在cmp中)
2.然后遍历到所在的点,这个点之前的点输出的dp值均为-1,因为x1*y2-x2*y1<0
3,从该点之后的点进行操作
4.如果suan(start,i)==0,那么该点对应为-1,直接下一个数
5.每当该点a可以到达的时候,就把该点存储起来,然后遍历下一个点b,从基本点到b的t值如果>基本点到a的最小t值加a与b的t,那么就动态更新基本点到b的值
6.最后输出每个点的dp值即可。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+5; struct node { ll x,y; int pos; }s[maxn]; bool cmp(const node &x,const node &y) { long long temp=x.x*y.y-x.y*y.x; if(temp) { return temp>0; } else { return x.x*x.x+x.y*x.y>y.x*y.x+y.y*y.y; } } ll suan(int i,int j) { return s[i].x*s[j].y-s[j].x*s[i].y; } ll dp[maxn]; int sta[maxn]; int main() { int n,pos,start,top=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld %lld",&s[i].x,&s[i].y); s[i].pos=i; } memset(dp,-1,sizeof(dp)); sort(s+1,s+1+n,cmp); scanf("%d",&pos); for(int i=1;i<=n;i++){ if(s[i].pos==pos) { start=i; break; } } sta[top=1]=start; dp[pos]=0; for(int i=start+1;i<=n;i++) { if(suan(start,i)==0) continue; while(top>1&&suan(sta[top-1],sta[top])==0) --top;//防止经过一系列出栈后,栈顶点与栈顶的下一个元素的t值为0. while(top>1&&suan(sta[top],i)+dp[s[sta[top]].pos]>=suan(sta[top-1],i)+dp[s[sta[top-1]].pos]) --top; dp[s[i].pos]=dp[s[sta[top]].pos]+suan(sta[top],i);//更新数值 sta[++top]=i;//栈的作用 } for(int i=1;i<=n;i++) { printf("%lld\n",dp[i]); } return 0; }