zoukankan      html  css  js  c++  java
  • luoguP1081 开车旅行 解题报告

    luoguP1081 开车旅行

    题意

    (n) 个城市 ((1 le n le 10^5)), 呈东西方向一字排开, 城市 (i) 的海拔为 (h[i]), ((-10^9 le h[i] le 10^9)), 两个城市 (i,j) 之间的距离为 (|h[i]-h[j]|).

    (A,B) 两人开车旅行, 从西向东行驶, 每天都能且只能沿着正方向从一个城市到达另一个城市, 第一天 (A) 开车, 之后他们每天交替开车.
    (A) 的驾驶风格为每次开到离当前城市第二近的城市,
    (B) 的驾驶风格为每次开到离当前城市最近的城市.

    有两个问题 :

    1. 给定 (x0), 求在行驶总距离不超过 (x0) 的条件下, 从哪个城市出发, 能使得 (A) 驾驶的距离 与 (B) 驾驶的距离 之比最小.
    2. 给定 (m)(s,x) ((1 le m le 10^5)), 分别代表出发的城市和行驶的最大距离, 求 (A,B) 各自的驾驶距离.

    思路

    其实想到倍增的话这道题就不怎么难了 (然而我是听别人说了这道题是倍增之后再去做的....)

    由于从每个城市出发, 下一次到达的城市以及经过的距离是一定的, 所以可以先预处理出每座城市往后的最近城市和次近城市,
    然后再预处理出 (g[i][k],f1[i][k],f2[i][k]), 分别表示从点 (i) 出发, 经过 (2^k) 座城市后到达的城市, (A) 的行驶距离, (B) 的行驶距离.

    最近城市和次进城市我是用 set 来处理, 然后因为 STL 运用不熟练, 还调了一段时间...

    总的来说这道题还算简单, 就是预处理时有一些细节还是要注意的.

    代码

    #include<bits/stdc++.h>
    #define ll long long
    #define itr iterator
    #define lb lower_bound
    using namespace std;
    const int N=1e5+7;
    const int L=20;
    const ll inf=1e17;
    int n,m,f[N][3],g[N][L+7];
    ll h[N],s1[N][L+7],s2[N][L+7];
    struct city{
    	int id;
    	ll h;
    	bool operator < (const city x) const{ return h<x.h; }
    	bool operator <= (const city x) const{ return h<=x.h; }
    	bool operator > (const city x) const{ return h>x.h; }
    	bool operator >= (const city x) const{ return h>=x.h; }
    	bool operator == (const city x) const{ return h==x.h; }
    }a[N],fs[4];
    set<city> S;
    int now;
    bool rule(city x,city y){
    	ll tx=abs(x.h-a[now].h),ty=abs(y.h-a[now].h);
    	return tx==ty ?x.h<y.h :tx<ty;
    }
    ll dis(int x,int y){ 
    	if(x==0||y==0) return 0;
    	return abs(h[x]-h[y]); 
    }
    bool clsr(city a,city b,city x){
    	ll ta=abs(a.h-x.h),tb=abs(b.h-x.h);
    	if(ta==tb) return a.h<b.h;
    	else return ta<tb;
    }
    void pre(){
    	S.insert(a[n]);
    	// 各种丑陋的分类讨论...
    	for(int i=n-1;i>=1;i--){
    		now=i;
    		set<city>::itr it=S.lb(a[i]),it1,it2,it3;
    		if(it!=S.begin()){ it--; it1=it; it++; }
    		else it1=it;
    		if(it1!=S.begin()){ it1--; it3=it1; it1++; }
    		else it3=it1;
    		if(it!=S.end()){ it++; it2=it; it--; }
    		else{ it2=it=it1; }
    		if(it2==S.end()) it2--;
    		fs[1]=*it1; fs[2]=*it; fs[3]=*it2;
    		city t3=*it3,t2=*it2;
    		if(it3!=it1&&clsr(t3,t2,a[i])) fs[3]=*it3;
    		sort(fs+1,fs+4,rule);
    		if(fs[1]==fs[2]){
    			if(fs[1]==fs[3]) f[i][1]=0;
    			else f[i][1]=fs[3].id;
    		}
    		else f[i][1]=fs[2].id;
    		f[i][2]=fs[1].id; 
    		S.insert(a[i]);
    	}
    	for(int i=n;i>=1;i--){
    		g[i][0]=f[i][1];
    		s1[i][0]=dis(i,f[i][1]);
    		g[i][1]=f[f[i][1]][2];
    		s1[i][1]=dis(i,f[i][1]);
    		s2[i][1]=dis(f[i][1],g[i][1]);
    		for(int k=2;k<=L;k++){
    			g[i][k]=g[g[i][k-1]][k-1];
    			s1[i][k]=s1[i][k-1]+s1[g[i][k-1]][k-1];
    			s2[i][k]=s2[i][k-1]+s2[g[i][k-1]][k-1];
    		}
    	}
    }
    void find(int s,ll x,ll &t1,ll &t2){
    	t1=t2=0;
    	for(int i=L;i>=0;i--)
    		if(g[s][i]&&s1[s][i]+s2[s][i]<=x){
    			x-=s1[s][i]+s2[s][i];
    			t1+=s1[s][i];
    			t2+=s2[s][i];
    			s=g[s][i];
    		}
    }
    int run(ll x0){
    	int ans=0; h[0]=-inf;
    	ll res1=0,res2=0,t1=0,t2=0;
    	for(int i=1;i<=n;i++){
    		find(i,x0,t1,t2);
    		if(!t2&&res2) continue;
    		if(res1*t2>t1*res2||(res1*t2==t1*res2&&h[i]>h[ans])){
    			ans=i;
    			res1=t1; res2=t2;
    		}
    	}
    	return ans;
    }
    int main(){
    //	freopen("drive1.in","r",stdin);
    //	freopen("drive.out","w",stdout);
    	cin>>n;
    	for(int i=1;i<=n;i++){ 
    		scanf("%lld",&h[i]);
    		a[i].id=i; a[i].h=h[i];
    	}
    	pre();
    	ll x0; scanf("%lld",&x0);
    	printf("%d
    ",run(x0));
    	cin>>m; int s; ll x,t1,t2;
    	for(int i=1;i<=m;i++){
    		scanf("%d%lld",&s,&x);
    		find(s,x,t1,t2);
    		printf("%lld %lld
    ",t1,t2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [Oracle维护工程师手记]一次升级后运行变慢的分析
    [Oracle运维工程师手记] 如何从trace 文件,判断是否执行了并行
    Top Page
    Python 输出文件内容到网络端口
    [Spark][Streaming]Spark读取网络输入的例子
    [Spark]如何设置使得spark程序不输出 INFO级别的内容
    linux 利器
    C++ 资源大全
    Who is using Asio?
    服务器开发知识要点
  • 原文地址:https://www.cnblogs.com/BruceW/p/11846862.html
Copyright © 2011-2022 走看看