zoukankan      html  css  js  c++  java
  • noip2012开车旅行 题解

    题目大意:

      给出n个排成一行的城市,每个城市有一个不同的海拔。定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近。有两个人轮流开车,从左往右走。A每次都选最近的,B每次都选次近的。旅行时有一个总路程x,如果两个人的总路程>x 或 有一个人无法按照自己的原则选择目的城市,旅行就终止。

      有两个问:

      1.给出x0,求从哪一个城市出发,使得A走的路程/B走的路程最小。如果B走的路程=0,则比值视为无穷大。如果有多个城市满足要求,则输出海拔最高的那个城市。

      2.给出x和s(出发城市),求旅行终止是A的路程和B的路程。

    题解:

    【数据范围】
    对于30%的数据,有1≤N≤20,1≤M≤20;
    对于40%的数据,有1≤N≤100,1≤M≤100;
    对于50%的数据,有1≤N≤100,1≤M≤1,000;
    对于70%的数据,有1≤N≤1,000,1≤M≤10,000;
    对于100%的数据,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,
    0≤X0≤1,000,000,000,1≤S
    i≤N,0≤Xi≤1,000,000,000,数据保证Hi 互不相同。

     先想骗分。。。

    • 50分

    对于50%的数据还是很好骗的。每次旅行都直接模拟行走,每次找一个最近或次近,时间O(N*N)。

    对于第一问直接枚举起点。时间复杂度为O(N*N*M + N*N*N)

    • 70分

    发现50分算法主要是 每次都要找下一个城市 耗费了太多时间,于是干脆直接预处理,O(N*N),总时间O(N*M + N*N)

    • 满分

    还是想想改进。。。70分算法的预处理太傻逼了。。其实我们是要每次找到一个海拔与当前城市相差最少的城市。所以算法就有很多种了……比如离散化+链表,双向链表,平衡树(其实用set的话程序比双向链表还好打,因为二分stl都给你弄好了。。)

    这里主要介绍下双向链表的做法:就是按高度排序,然后链起来。按城市原始位置从左到右处理接下来的城市是哪个,然后将自己删掉(因为接下来就没用了)。如何找接下来的那个?就是往链表的左右两边找两层,记一个最近和次近。

    然后预处理就可以优化到O(N)

    then???

    发现其实这是一棵树。。。

    于是倍增

    预处理已经处理出2^0的情况了。接下来直接动规就好了,就可以预处理出每个点的2^i的父亲是谁,以及A走了多少,B走了多少。

    then???

    现在问题就是给定总路程要怎么求出AB走的路程。

    问题可以转化成给定总路程求走了几次。然后就可以用上先前的预处理。假设走了t次,则t肯定可以表示成二进制,而且只有logn位的二进制数。于是可以枚举这一位取0还是1。调用先前处理的数组,看加上所增加的路程后会不会超出x,不会就是1,会就是0。

    于是问题就完美解决了!

    //代码(巨丑无比)

    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <map>
    const int N = 100000 + 9;
    struct Link
    {
    	int nxt,pre;
    }link[N];
    int TOT,n,idx[N];
    struct CITY
    {
    	int h,idx;
    }city[N];
    struct info
    {
    	int u;
    	long long dis1,dis2;
    	info(const int a = 0,const long long b = 0,const long long c = 0):u(a),dis1(b),dis2(c){}
    }f[20][N][2];
    //0: B
    //1: A
    inline bool cmp(const CITY &lhs,const CITY &rhs){return lhs.h < rhs.h;}
    inline int getnext(const int i,const int t){return i?t:(t^1);}
    void update(const int i,const int j,const int t)
    {
    	const int nxt = f[i - 1][j][t].u;
    	const long long dis1 = f[i - 1][j][t].dis1,dis2 = f[i - 1][j][t].dis2;
    	if (nxt) {
    		info tmp;
    		if ((tmp = f[i - 1][nxt][getnext(i - 1,t)]).u)
    			f[i][j][t] = info(tmp.u,dis1 + tmp.dis1,dis2 + tmp.dis2);
    	}
    }
    std::pair<int,int> go(int s,long long x)
    {
    	std::pair<int,int>tmp(0,0);
    	int turn = 1; // A
    	for (int i = TOT; i >= 0; --i) {
    		if (!f[i][s][turn].u) continue;
    		if (x - f[i][s][turn].dis1 - f[i][s][turn].dis2 < 0) continue;
    		x -= f[i][s][turn].dis1 + f[i][s][turn].dis2;
    		tmp.first  += f[i][s][turn].dis2;
    		tmp.second += f[i][s][turn].dis1;
    		turn = getnext(i,turn);
    		s = f[i][s][turn].u;
    	}
    	return tmp;
    }
    inline void check(const int id_p,const int id_n,int &Min_h1,int &Min_i1,int &Min_h2,int &Min_i2)
    {
    	if (!id_n) return;
    	const int dis = std::abs(city[id_p].h - city[id_n].h);
    	if (dis < Min_h1 || dis == Min_h1 && city[id_n].h < city[Min_i1].h) {
    		Min_h2 = Min_h1;
    		Min_i2 = Min_i1;
    		Min_h1 = dis;
    		Min_i1 = id_n;
    	}else if (dis < Min_h2 || dis == Min_h2 && city[id_n].h < city[Min_i2].h) {
    		Min_h2 = dis;
    		Min_i2 = id_n;
    	}
    }
    inline long long cmp2(const std::pair<int,int>lhs,const std::pair<int,int>rhs)
    {
    	if (!lhs.second && !rhs.second) return 0;
    	else if (!lhs.second) return 1;
    	else if (!rhs.second) return -1;
    	else return 1ll * lhs.first * rhs.second - 1ll * rhs.first * lhs.second;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("drive.in","r",stdin);
    	freopen("drive.out","w",stdout);
    	#endif
    	scanf("%d",&n);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%d",&city[i].h);
    		city[i].idx = i;
    	}			
    	std::sort(city + 1,city + 1 + n,cmp);
    	for (int i = 1; i < n; ++i) {
    		link[i].nxt = i + 1;
    		link[i + 1].pre = i ;
    		idx[city[i].idx] = i;
    	}
    	idx[city[n].idx] = n;
    	for (int i = 1; i <= n; ++i) {
    		int id = idx[i],Min_h1 = 0x7fffffff,Min_i1 = 0,Min_h2 = 0x7fffffff,Min_i2 = 0;
    		check(id,link[id].pre,           Min_h1, Min_i1, Min_h2, Min_i2);
    		check(id,link[id].nxt,           Min_h1, Min_i1, Min_h2, Min_i2);
    		check(id,link[link[id].pre].pre, Min_h1, Min_i1, Min_h2, Min_i2);
    		check(id,link[link[id].nxt].nxt, Min_h1, Min_i1, Min_h2, Min_i2);
    		f[0][i][0] = info(city[Min_i1].idx,Min_h1,0);
    		f[0][i][1] = info(city[Min_i2].idx,0,Min_h2);
    		if (link[id].nxt) link[link[id].nxt].pre = link[id].pre;
    		if (link[id].pre) link[link[id].pre].nxt = link[id].nxt;
    	}
    	TOT = static_cast<int>(ceil(log2((double)n)));
    	for (int i = 1; i <= TOT; ++i)
    		for (int j = 1; j <= n; ++j) {
    			update(i,j,0);
    			update(i,j,1);
    		}
    	int x;
    	scanf("%d",&x);
    	std::pair<int,int>ans;
    	int ans_pos = 0;
    	ans.first = 1; ans.second = 0;
    	for (int i = 1; i <= n; ++i) {
    		std::pair<int,int>tmp = go(i,x);
    		if (cmp2(tmp,ans) < 0) {
    			ans = tmp;
    			ans_pos = i;
    		}else if (cmp2(tmp,ans) == 0 && city[idx[ans_pos]].h < city[idx[i]].h) {
    			ans = tmp;
    			ans_pos = i;
    		}
    	}
    	printf("%d
    ",ans_pos);
    	int m;
    	scanf("%d",&m);
    	for (int i = 1,x,s; i <= m; ++i) {
    		scanf("%d%d",&s,&x);
    		std::pair<int,int> tmp = go(s,x);
    		printf("%d %d
    ",tmp.first,tmp.second);
    	}
    }
    

      

  • 相关阅读:
    CentOS 7 SSH远程证书登陆
    Keepalived安装配置入门
    Docker-Compose 一键部署Ningx+.Net Core+Redis集群
    .Net Core Cookie跨站点共享 会话保持
    .Net Core EF Core之Sqlite使用及部署
    CentOS 7 Fail2ban防暴力破解
    CentOS 7 Nginx安装配置
    CentOS 7 Firewalld 常用操作
    Linux 修改SSH端口及禁用ROOT远程SSH登陆
    Mysql MariaDB安装
  • 原文地址:https://www.cnblogs.com/lazycal/p/noip2012-day1-t3.html
Copyright © 2011-2022 走看看