zoukankan      html  css  js  c++  java
  • UOJ#24. 【IOI2014】Rail 交互题

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ24.html

    题解

      我们将 C 型车站称为 左括号 '(', D 型车站称为右括号 ')' ,设括号 i 的位置为 p[i] 。

      首先,我们用点 0 把所有位置都询问一遍,那么距离最近的那个点一定是在 0 右边的第一个 ')' 。

      设 0 位置为 x ,距离 0 最近的 )为 y,那么在 x 与 y 之间只可能有( 。

      现在我们可以将所有括号分成 3 类: x 左侧的, x 与 y 之间的,y 右侧的。

      对于一个括号 i ,如果 dis(x,y) + dis(y,i) = dis(x,i) ,那么 i 一定在 y 的左边,否则一定在 y 的右边。

      当 i 在 y 的左边时,由于 x 与 y 之间只有( ,所以当 dis(x,y) > dis(y,i) 时, i 在 x 与 y 之间,否则 i 在 x 左侧。

      注意到在 x 与 y 之间的都是可以直接确定类型和位置的,所以我们考虑左侧和右侧。

      由于左侧和右侧的两个子问题是对称的,做法类似,所以这里只介绍右侧的:

      我们把剩下的括号按照与 x 的距离排序。然后从小到大依次处理:

      假设当前最右侧的 )为 r (初始 r = y)。假设当前处理到括号 i ,由于是排过序的,所以 i 只有两种情况:

      1.  i 在 r 的右边,是 )。

      2.  i 在 r 的左边,是( 。

      假装 i 在 r 的左边,那么从 x 到 i 必然要经过一个 ),而且是在 i 右边距离 i 最近的 )。那么 r 距离它多少呢?

    $$len = cfrac{dis(x,r)+dis(r,i)-dis(x,i)}{2}$$

      那么如果 i 在 r 的右边,这个式子表示什么?——是 r 到它左边距离它最近的( 的距离,它可能没有被访问过,但它一定不是 )。

      那么我们注意到,p[i] - len 这个位置如果是 ),那么它由于它距离 x 更近,所以它已经被访问过了。所以,如果 p[i] - len 位置上是一个已经被访问过的 ),那么 i 在 r 的左边,否则i 一定在 r 的右边。

      于是我们就可以在 3(n-1) 次询问的限制内解决这个问题了。

    代码

    #include "rail.h"
    #pragma GCC optimize("Ofast","inline")
    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    typedef vector <int> vi;
    const int N=5005;
    #define C(a,b) (type[a]=1,p[a]=b,vis[a]=1)
    #define D(a,b) (type[a]=2,p[a]=b,vis[a]=1)
    unordered_map <int,int> Dis[N];
    int Ask(int a,int b){
    	if (a==b)
    		return 0;
    	if (Dis[a][b])
    		return Dis[a][b];
    	return Dis[a][b]=Dis[b][a]=getDistance(a,b);
    }
    int x,y;
    vi dx,dy,ids;
    int vis[N];
    set <int> SL,SR;
    bool cmpD(int a,int b){
    	return dx[a]<dx[b];
    }
    void findLocation(int n,int p0,int *p,int *type){
    	For(i,0,n-1)
    		Dis[i].clear();
    	dx.resize(n);
    	dy.resize(n);
    	ids.clear();
    	clr(vis);
    	x=0;
    	For(i,0,n-1)
    		dx[i]=Ask(x,i),ids.pb(i);
    	sort(ids.begin(),ids.end(),cmpD);
    	y=ids[1];
    	C(x,p0);
    	if (n==1)
    		return;
    	D(y,p0+dx[y]);
    	For(i,0,n-1)
    		dy[i]=Ask(y,i);
    	int l=x,r=y,MaxM=0;
    	for (auto i : ids)
    		if (!vis[i]&&dx[y]+dy[i]==dx[i]&&dy[i]<dx[y]){
    			C(i,p[y]-dy[i]);
    			MaxM=max(MaxM,p[i]-p[x]);
    		}
    	int sy=p[y]-(dx[y]-MaxM)*2;
    	SL.clear(),SL.insert(dy[x]);
    	SR.clear(),SR.insert(dx[y]);
    	for (auto i : ids)
    		if (!vis[i]){
    			if (dx[y]+dy[i]==dx[i]){
    				int len=(dy[l]+Ask(l,i)-dy[i])/2;
    				if (!SL.count(dy[l]-len)){
    					C(i,p[y]-dy[i]);
    					SL.insert(dy[i]);
    					l=i;
    				}
    				else
    					D(i,p[l]+Ask(l,i));
    			}
    			else {
    				int len=(dx[r]+Ask(r,i)-dx[i])/2;
    				if (!SR.count(dx[r]-len)){
    					D(i,p[x]+dx[i]);
    					SR.insert(dx[i]);
    					r=i;
    				}
    				else
    					C(i,p[r]-Ask(r,i));
    			}
    		}
    }
    

      

  • 相关阅读:
    Win7+Ubuntu11.10(EasyBCD硬盘安装)
    ubuntu 定时执行php
    Javascript如何判断一个变量是普通变量还是数组还是对象?
    CSS3 Gradient
    CSS3 transform rotate(旋转)锯齿的解决办法
    win2003中Apache开启gzip功能
    CSS3图形,Css画图,Css3三角形
    apache开启gzip的压缩功能
    标签:article
    人人FED CSS编码规范
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ24.html
Copyright © 2011-2022 走看看