zoukankan      html  css  js  c++  java
  • 「清华集训 2017」我的生命已如风中残烛

    题目描述:

    链接

    思路:

    (小声:离线赛遇到这个大样例真的自闭)

    暴力思路就是往下找下一个会换到的钉子,然后只到没有可以达到的钉子为止。

    然后可以发现会出现围着几个钉子绕圈的情况,那就可以直接算出在这一段上绕的次数。(根据官方题解所说最多只会出现(log L)次循环,因为每次长度会减少至少一半)

    这样复杂度就是(O(n^2mlogL)),60pts (60分的思路考试被自己打成了20分,给的大样例仿佛没有)

    可以发现复杂度就是在寻找下一个钉子上,这时候可以考虑预处理,对于每个钉子(i),记录下其他钉子与它的连线和(x)轴正方向的极角,按极角排序(如果是负数的时候直接加上2(pi)

    这样找的时候就可以直接二分然后往下找(不过这样其实复杂度上限也没变,但是可以过……)

    //「清华集训 2017」我的生命已如风中残烛
    #include<bits/stdc++.h>
    #define M 505
    #define db long double
    #define ll long long
    using namespace std;
    void Rd(ll &res) {
    	res=0;
    	char c;
    	int fl=1;
    	while(c=getchar(),c<48)if(c=='-')fl=-1;
    	do res=(res<<1)+(res<<3)+(c^48);
    	while(c=getchar(),c>=48);
    	res*=fl;
    }
    int T,n,m;
    struct Point {
    #define P Point
    	ll x,y;
    	P operator+(const P&_)const {
    		return (P)<%x+_.x,y+_.y%>;
    	}
    	P operator-(const P&_)const {
    		return (P)<%x-_.x,y-_.y%>;
    	}
    	ll operator*(const P&_)const {
    		return x*_.x+y*_.y;
    	}
    	ll operator^(const P&_)const {
    		return x*_.y-_.x*y;
    	}
    } a[M];
    const db eps=1e-15;
    const db pi=acos(-1);
    db calc(P A,P B) {
    	return sqrt(1.0*(A.x-B.x)*(A.x-B.x)+1.0*(A.y-B.y)*(A.y-B.y));
    }
    struct Node {
    	int id;
    	db l,ang;
    	bool operator<(const Node&_)const {
    		if(abs(ang-_.ang)<=eps)return l>_.l;
    		return ang>_.ang;
    	}
    } A[M],To[M][M];
    struct P1 {
    #define N 20000005
    	int stk[N];
    	db Len[N],len,pl;
    	bool vis[M];
    	void add(int id,int y,P L,P R) {
    		P x=R-L;
    		db ang=atan2(x.y,x.x);
    		if(ang<0)ang+=2*pi;
    		To[id][y]=(Node)<%y,calc(L,R),ang%>;
    	}
    	void solve() {
    		P s,t;
    		ll l,ans;
    		for(int i=1; i<=n; i++) {
    			for(int j=1; j<=n; j++)add(i,j,a[i],a[j]);
    			sort(To[i]+1,To[i]+n+1);
    		}
    		while(m--) {
    			Rd(s.x),Rd(s.y),Rd(t.x),Rd(t.y),Rd(l);
    			for(int i=1; i<=n; i++)add(0,i,s,a[i]);
    			sort(To[0]+1,To[0]+n+1);
    			int r=0,la=0,L=1,R=0,id=0;
    			len=1.0*l,ans=1,Len[0]=0;
    			for(int i=1; i<=n; i++)vis[i]=0;
    			while(1) {
    //				printf("%d ",la);
    				P now=t-s;
    				db ang=atan2(now.y,now.x),l=len;
    				if(ang<0)ang+=2*pi;
    				int x=-1,p=lower_bound(To[la]+1,To[la]+n+1,(Node)<%1,l,ang%>)-To[la];
    				if(p>n)p=1;
    				for(int i=1; i<=n; i++) {
    					if(To[la][p].id==la||abs(To[la][p].ang-ang)<=eps);
    					else if(To[la][p].l<=len) {
    						x=To[la][p].id;
    						break;
    					}
    					p++;
    					if(p==n+1)p=1;
    				}
    				if(x==-1)break;
    				pl=calc(s,a[x]),ans++,len-=pl;
    				if(ans>3) {
    					if(vis[x]) {
    						while((L<=R)&&stk[L]!=x)vis[stk[L]]=0,L++;//找到上一次这个数出现的位置
    						ll t=R-L+1,k=len/(Len[R]-Len[L]+pl);
    						ans+=1ll*t*k,len-=k*(Len[R]-Len[L]+pl);
    						for(int i=L+1; i<=R; i++)vis[stk[i]]=0;
    						R=L,Len[L]=0;
    					} else vis[x]=1,stk[++R]=x,Len[R]=Len[R-1]+pl;
    				}
    				t=(P)<%a[x].x*2-s.x,a[x].y*2-s.y%>,s=a[x],la=x;
    			}
    			printf("%lld
    ",ans);
    		}
    	}
    } p1;
    int main() {
    	freopen("life.in","r",stdin);
    	freopen("life.out","w",stdout);
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d",&n,&m);
    		for(int i=1; i<=n; i++)Rd(a[i].x),Rd(a[i].y);
    		p1.solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    tar解压时如何去掉第一级目录并解压到指定目录?
    ubuntu下容器无法启动报错"failed to start daemon: failed to dial "/run/containerd/containerd.sock": unknown service containerd.services.namespaces.v1.Namespaces: not implemented"如何处理?
    redis用法介绍
    Map.putAll()用法
    Random,ThreadLocalRandom,SecureRandom的几点思考
    SOAPUI---使用断言
    AutoUpdater迁移到Github
    VirtualBox: linux 没有权限访问共享文件夹的问题
    MakeFIle: 解决“/bin/bash^M: bad interpreter: No such file or directory”的问题
    ubuntu 备忘录
  • 原文地址:https://www.cnblogs.com/cly1231/p/12951516.html
Copyright © 2011-2022 走看看