【NOIP2012】开车旅行(倍增+STL)

【NOIP2012】开车旅行
纪念一下这个大毒瘤
先用multiset处理一下在每个城市时小A和小B的下一个到达的。
一个一个地跳肯定会超时,所以考虑倍增。
f[i][A/B][k]表示从城市i出发,A/B先开车,走(2^k)天所到达的城市。
fa[i][A/B][k]表示从城市i出发,A/B先开车,走(2^k)天小A走的路程。
fb[i][A/B][k]表示从城市i出发,A/B先开车,走(2^k)天小B走的路程。
初始化:

 //0表示小A, 1表示小B higha表示小A到达的下一个城市,highb同理
f[i][0][0] = higha; f[i][1][0] = highb;
fa[i][0][0] = abs(h[i] - h[higha]);
fb[i][1][0] = abs(h[i] - h[highb]);

转移

//这里j表示天数的幂,即2^j天,k表示小A或小B
for(int j = 1;j <= 23; j++) {
      for(int k = 0; k < 2; k++) {
	      if(j == 1) {//走两天时单独处理
	              f[i][k][1] = f[f[i][k][0]][1 - k][0];
		      fa[i][k][1] = fa[i][k][0] + fa[f[i][k][0]][1 - k][0];
		      fb[i][k][1] = fb[i][k][0] + fb[f[i][k][0]][1 - k][0];
	      } else {
	            f[i][k][j] = f[f[i][k][j - 1]][k][j - 1];
	            fa[i][k][j] = fa[i][k][j - 1] + fa[f[i][k][j - 1]][k][j - 1];
	            fb[i][k][j] = fb[i][k][j - 1] + fb[f[i][k][j - 1]][k][j - 1];
	      }
      }
}

完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long lld;
const int N = 100100;
const int inf = 2e9;
int a[N], n, h[N];
int f[N][2][25], fa[N][2][25], fb[N][2][25];//0 : A, 1 : B
//A 次近 B 最近
struct node {
	int id, high;
	friend bool operator < (node a, node b) {//重载运算符由小到大排序
		return a.high < b.high;
	}
};
multiset<node> s;
void get_next() {
	h[0] = inf; h[n + 1] = -inf;
	node st;
	st.id = 0, st.high = inf;
	s.insert(st); s.insert(st);
	st.id = n + 1, st.high = -inf;
	s.insert(st); s.insert(st);
	set<node>::iterator q;
	for(int i = n; i >= 1; i--) {
		int higha, highb;
		node city; city.high = h[i], city.id = i;
		s.insert(city);
		q = s.lower_bound(city);
		q--;
		int per = (*q).id, perh = (*q).high;
		q++, q++;
		int nxt = (*q).id, nxth = (*q).high;
		q--;
		if(abs(perh - h[i]) <= abs(nxth - h[i])) { //per min
			highb = per;
			q--, q--;
			if(abs(nxth - h[i]) < abs(h[i] - (*q).high)) {
				higha = nxt;
			} else higha = (*q).id;
		} else { //nxt min
			highb = nxt;
			q++, q++;
			if(abs(perh - h[i]) <= abs(h[i] - (*q).high)) {
				higha = per;
			} else higha = (*q).id;
		}
		f[i][0][0] = higha; f[i][1][0] = highb;
		fa[i][0][0] = abs(h[i] - h[higha]);
		fb[i][1][0] = abs(h[i] - h[highb]);
		for(int j = 1;j <= 23; j++) {
			for(int k = 0; k < 2; k++) {
				if(j == 1) {
					f[i][k][1] = f[f[i][k][0]][1 - k][0];
					fa[i][k][1] = fa[i][k][0] + fa[f[i][k][0]][1 - k][0];
					fb[i][k][1] = fb[i][k][0] + fb[f[i][k][0]][1 - k][0];
				} else {
					f[i][k][j] = f[f[i][k][j - 1]][k][j - 1];
					fa[i][k][j] = fa[i][k][j - 1] + fa[f[i][k][j - 1]][k][j - 1];
					fb[i][k][j] = fb[i][k][j - 1] + fb[f[i][k][j - 1]][k][j - 1];
				}
			}
		}
	}
}
int xa, xb;
void calc(int start, int x) {
	int st = start;
	xa = 0, xb = 0;
	for(int i = 23; i >= 0; i--) {
		if(f[st][0][i] && xa + xb + fa[st][0][i] + fb[st][0][i] <= x) {
			xa += fa[st][0][i]; xb += fb[st][0][i];
			st = f[st][0][i];
		}
	}
	return ;
}
void solve1() {
	int x0; scanf("%d", &x0);
	double ratio = inf * 1.0; int ans = 0;
	for(int i = 1; i <= n; i++) {
		calc(i, x0);
		if(xb == 0) {
			xb = 1; xa = inf;
		}
		if((1.0 * double(xa) / double(xb)) < ratio) {
			ratio = double(xa) / double(xb); ans = i;
		} else if(double(xa) / double(xb) == ratio) {
			if(h[i] > h[ans]) ans = i;
		}
	}
	printf("%d
", ans);
}
void solve2() {
	int m; scanf("%d", &m);
	for(int i = 1, x0, st; i <= m; i++) {
		scanf("%d%d", &st, &x0);
		calc(st, x0);
		printf("%d %d
", xa, xb);
	}
}
int main() {
//	freopen("data.in", "r", stdin);
//	freopen("data.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &h[i]);
	}
	get_next();
	solve1();
	solve2();
	return 0;
}
原文地址:https://www.cnblogs.com/mcggvc/p/13796053.html