zoukankan      html  css  js  c++  java
  • 题解 P1081 【开车旅行】

    题目链接

    Solution 开车旅行

    题目大意:有(n)座城市,每座城市有一个海拔高度,你只能从编号小的往编号大的移动。定义两城市距离为海拔高度差的绝对值。小A开车会去离他第二近的城市,小B开车会去离他最近的城市。(如果距离相同则认为海拔低的近)。两人开车的距离之和不能超过(X),问给定一个(X)从哪座城市出发小A小B行驶距离之比最小,(一样小的认为海拔高的小),问给定出发点(s)(X),小A小B分别行驶距离

    倍增


    分析:首先关键在于给定(s)(X)的时候快速算出他俩分别走了多远,这样第一问就可以枚举来回答

    不难想到暴力算法,我们把A,B都走一次称为一轮,那么我们一轮一轮的走,直到走不动为止。因为A先走所以最后单独考虑A即可

    这样的时间复杂度单次(O(n)),无法承受。我们关注点在一轮一轮的走太花时间,因此我们可以倍增来走,单次时间复杂度降至(O(logn))

    麻烦的地方在于预处理A和B会走到哪儿,不难想到,假如我们对于序列每一个后缀建一棵平衡树,那么小B就是在前驱和后继里面取最优。小A就是加上前驱的前驱,后继的后继然后取次优,这个我们用(set)来维护,(vector)暴力排序即可(反正最多只有(4)个元素)

    然后关于倍增,我们预处理出从每个位置(pos)(2^i)次方轮后走到哪儿,其中A走了多远,B走了多远即可

    代码要开C++11

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #include <set>
    #include <vector>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 100,maxd = 25;
    inline int read(){
    	int x = 0,f = 1;char c = getchar();
    	while(!isdigit(c))f = c == '-' ? -1 : f,c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x * f;
    }
    struct SetNode{
    	int pos,v;
    	bool operator < (const SetNode &rhs)const{
    		return v < rhs.v;
    	}
    };
    int val[maxn],nxtA[maxn],nxtB[maxn],nxt[maxn][maxd + 1],n,m,X0,s,x,ans;
    long double tmp;
    ll disA[maxn][maxd + 1],disB[maxn][maxd + 1];
    inline int getdis(int a,int b){return abs(val[a] - val[b]);}
    inline void init(){
    	set<SetNode> s;
    	vector<SetNode> vec;
    	typedef set<SetNode>::iterator iter;
    	auto getpre = [&](iter x){return x == s.begin() ? x : --x;};
    	auto getnxt = [&](iter x){return x == s.end() ? x : ++x;};
    	for(int i = n;i >= 1;i--){
    		iter tmp = s.upper_bound(SetNode{0,val[i]});
    		for(auto it = getpre(getpre(getpre(tmp)));it != getnxt(getnxt(getnxt(tmp)));it++)
    			vec.push_back(*it);
    		sort(vec.begin(),vec.end(),[&](const SetNode &a,const SetNode &b){
    			int ta = abs(val[i] - a.v),tb = abs(val[i] - b.v);
    			return ta == tb ? a.v < b.v : ta < tb;
    		});
    		nxtA[i] = vec.size() >= 2 ? vec[1].pos : -1;
    		nxtB[i] = vec.size() >= 1 ? vec[0].pos : -1;
    		s.insert(SetNode{i,val[i]});
    		vec.clear();
    	}
    	for(int i = 1;i <= n;i++){
    		nxt[i][0] = nxtA[i] == -1 ? -1 : (nxtB[nxtA[i]] == -1 ? -1 : nxtB[nxtA[i]]);
    		disA[i][0] = nxtA[i] == -1 ? -1 : getdis(i,nxtA[i]);
    		disB[i][0] = nxtA[i] == -1 ? -1 : (nxtB[nxtA[i]] == -1 ? -1 : getdis(nxtA[i],nxtB[nxtA[i]]));
    	}
    	for(int d = 1;d <= maxd;d++)
    		for(int i = 1;i <= n;i++){
    			nxt[i][d] = nxt[i][d - 1] == -1 ? -1 : (nxt[nxt[i][d - 1]][d - 1] == -1 ? -1 : nxt[nxt[i][d - 1]][d - 1]);
    			disA[i][d] = nxt[i][d] == -1 ? -1 : (disA[i][d - 1] + (nxt[i][d - 1] == -1 ? 0 : disA[nxt[i][d - 1]][d - 1]));
    			disB[i][d] = nxt[i][d] == -1 ? -1 : (disB[i][d - 1] + (nxt[i][d - 1] == -1 ? 0 : disB[nxt[i][d - 1]][d - 1]));
    		}
    }
    inline long double solve1(int pos){
    	x = X0;
    	ll resA = 0,resB = 0;
    	for(int d = maxd;d >= 0;d--)
    		if((x >= disA[pos][d] + disB[pos][d]) && nxt[pos][d] != -1 && disA[pos][d] != -1 && disB[pos][d] != -1)
    			resA += disA[pos][d],resB += disB[pos][d],x -= disA[pos][d] + disB[pos][d],pos = nxt[pos][d];
    	
    	if(disA[pos][0] != -1 && x >= disA[pos][0])resA += disA[pos][0];
    	return !resB ? (1e18) : (long double)resA / resB;
    }
    inline void solve2(){
    	ll ansA = 0,ansB = 0;
    	for(int d = maxd;d >= 0;d--)
    		if((x >= disA[s][d] + disB[s][d]) && nxt[s][d] != -1 && disA[s][d] != -1 && disB[s][d] != -1)
    			ansA += disA[s][d],ansB += disB[s][d],x -= disA[s][d] + disB[s][d],s = nxt[s][d];
    	
    	if(disA[s][0] != -1 && x >= disA[s][0])ansA += disA[s][0];
    	printf("%lld %lld
    ",ansA,ansB);
    }
    int main(){
    	n = read();
    	for(int i = 1;i <= n;i++)val[i] = read();
    	init();
    	X0 = read();
    	for(int i = 1;i <= n;i++){
    		long double t = solve1(i);
    		if(!ans || (t == tmp ? (val[i] > val[ans]) : (t < tmp)))
    			ans = i,tmp = t;
    	}
    	printf("%d
    ",ans);
    	m = read();
    	for(int i = 1;i <= m;i++)
    		s = read(),x = read(),solve2();
    	return 0;
    }
    
  • 相关阅读:
    latex在vim中的代码片段
    latex设置不同中英文字体
    React 路由基本配置
    React网络请求
    React生命周期函数
    React父子传值中propTypes defaultProps
    React父子组件传值
    React todolist案例和持久化实现
    React表单
    react事件对象 、键盘事件、 表单事件 、ref获取dom节点、React实现类似vue双向数据绑定
  • 原文地址:https://www.cnblogs.com/colazcy/p/11718962.html
Copyright © 2011-2022 走看看