[NOIP2012] 开车旅行
题目大意:在数轴上有(n)个不同高度的城市从西到东排列,定义(dis(i,j))为(i)城市到(j)城市的(abs(h_i,h_j)),有两个人(A)和(B)轮流开车从任意城市出发向东旅行,(A)一定是先开车的,他会选择去距离当前城市第二近的城市((dis)一样,去高度低的城市),走一定的里程,那么第二次(B)在开车,他会选择去距离当前的城市最近的城市((dis)一样,去高度低的城市),走一定的里程;如果对于(A,B)里程不够了,或者没有可以选的城市了,结束旅行.现在有两个询问
- 无论从哪个地方出发,给定里程数,求(A,B)开车里程的最小比值所在的旅行的出发地,如果有多个出发地的比值相同,取海拔高的
- 给定(m)组询问(S_i,X_i),求从(S_i)出发,不能超过(X_i)的里程的旅行中,(A)和(B)分别走过的里程值
Solution.70pts
数据范围比较小,模拟可过,不要什么图都拿邻接表存,然后我的深搜就写挂了
Code.70pts
一些操作还是很巧妙的
#include <iostream>
#include <cmath>
#include <cstdio>
const int N = 1005;
int n, x0;
int h[N], dis[N][N], one[N], two[N];
//学一下自己写abs
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &h[i]);
for(int i = 1; i <= n; ++i){
for(int j = i + 1; j <= n; ++j){
dis[i][j] = abs(h[i] - h[j]);
if(!one[i]){
one[i] = j;
}else if(dis[i][one[i]] > dis[i][j] || (dis[i][one[i]] == dis[i][j] && h[one[i]] > h[j])){
two[i] = one[i];
one[i] = j;
}else if(!two[i]){
two[i] = j;
}else if(dis[i][two[i]] > dis[i][j] || (dis[i][two[i]] == dis[i][j] && h[two[i]] > h[j])){
two[i] = j;
}
}
}
int x, a, b, c, ans;
scanf("%d", &x);
double tmp = 2147483647;
for(int i = 1; i <= n - 2; ++i){//n - 1 和 n 的旅程还没开始就结束了
a = b = 0;
c = i;
for(int j = 1; ; ++j){
if(j & 1){
if(!two[c] || dis[c][two[c]] + a + b > x) break;
a += dis[c][two[c]], c = two[c];
}else{
if(!one[c] || dis[c][one[c]] + a + b > x) break;
b += dis[c][one[c]], c = one[c];
}
}
if(b && a * 1.0 / b < tmp) tmp = a * 1.0 / b, ans = i;
else if(b && a * 1.0 / b == tmp){
if(h[ans] < h[i])
ans = i;
}
}
printf("%d
", ans);
int m;
scanf("%d", &m);
while(m--){
scanf("%d %d", &c, &x);
a = b = 0;
for(int j = 1; ; ++j){
if(j & 1){
if(!two[c] || dis[c][two[c]] + a + b > x) break;
a += dis[c][two[c]], c = two[c];
} else {
if(!one[c] || dis[c][one[c]] + a + b > x) break;
b += dis[c][one[c]], c = one[c];
}
}
printf("%d %d
", a, b);
}
return 0;
}
Solution.100pts
排序后运用双向链表(O(n))处理(one[i])和(two[i]),链表上的序号就代表了排序后的城市排名
为了方便,直接把(i-1,i+1,i-2,i+2)排序取前两名,然后倍增的搞,转移也方便
Attention.100pts
- (prepare)函数按照相对值的绝对值排序
- 双向链表里面删去结点,注意要直接将前驱后继连接,不可以变成(i-1)和(i+1),因为很可能(i-1)或(i+1)也是一个被删除的点
- 十分注意快读中位运算的优先级
Code.100pts
#include <iostream>
#include <cstdio>
#include <algorithm>
#define pf(x) printf("%d
", x)
using std::sort;
const int N = 1e5 + 10;
int n;
int pre[N], nxt[N], head[N], one[N], two[N], data[N];
int A[N][22], B[N][22], f[N][22];
int abs(int x) {
if (x >= 0) return x; return -x;
}
struct City{
int p, i;
bool operator < (const City &cmp) const {
return p < cmp.p;
}
}h[N];
struct QWQ{
int p, i;
bool operator < (const QWQ &cmp) const {
if(p == cmp.p){
return data[i] < data[cmp.i];
}
return p < cmp.p;
}
};
inline int read(){
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 3) + (x << 1) + (c ^ 48);//不括起来就出现了傻逼现象
c = getchar();
}
return x * f;
}
inline void get_dis(int af, int bf){
QWQ qwq[5];
int qwq_cnt = 0;
if(pre[af]) {
qwq[++qwq_cnt].p = abs(h[pre[af]].p - data[bf]);
qwq[qwq_cnt].i = h[pre[af]].i;
if(pre[pre[af]]){
qwq[++qwq_cnt].p = abs(h[pre[pre[af]]].p - data[bf]);
qwq[qwq_cnt].i = h[pre[pre[af]]].i;
}
nxt[pre[af]] = nxt[af];//delete
}
if(nxt[af]){
qwq[++qwq_cnt].p = abs(h[nxt[af]].p - data[bf]);
qwq[qwq_cnt].i = h[nxt[af]].i;
if(nxt[nxt[af]]){
qwq[++qwq_cnt].p = abs(h[nxt[nxt[af]]].p - data[bf]);
qwq[qwq_cnt].i = h[nxt[nxt[af]]].i;
}
pre[nxt[af]] = pre[af];//delete pre[nxt[af]] = af - 1;
}
sort(qwq + 1, qwq + qwq_cnt + 1);
if(qwq_cnt >= 1)one[bf] = qwq[1].i;
if(qwq_cnt >= 2)two[bf] = qwq[2].i;
return;
}
inline void prepare(){
for(int i = 1; i <= n; ++i){
if(two[i]) A[i][0] = abs(data[two[i]] - data[i]);
if(one[two[i]]) B[i][0] = abs(data[one[two[i]]] - data[two[i]]);
if(one[two[i]])f[i][0] = one[two[i]];
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
h[i].p = read();
h[i].i = i;
data[i] = h[i].p;
}
sort(h + 1, h + n + 1);
for(int i = 1; i <= n; ++i){
head[h[i].i] = i;
nxt[i] = i + 1;
pre[i] = i - 1;
if(i == n)
nxt[i] = 0;
}
for(int i = 1; i <= n; ++i)
get_dis(head[i], i);
prepare();
for(int i = 1; i <= 17; ++i){
for(int j = 1; j <= n; ++j){
A[j][i] = A[j][i - 1] + A[f[j][i - 1]][i - 1];
B[j][i] = B[j][i - 1] + B[f[j][i - 1]][i - 1];
f[j][i] = f[f[j][i - 1]][i -1];
}
}
int x0, a, b, c, z, ans;
double tmp = 2147483640;
scanf("%d", &x0);
for(int i = 1; i <= n; ++i){
a = b = 0, z = x0, c = i;
for(int j = 20; j >= 0; --j){
if(f[c][j] && z >= A[c][j] + B[c][j]){
a += A[c][j];
b += B[c][j];
z -= A[c][j] + B[c][j];
c = f[c][j];
}
}
if(A[c][0] <= z) a += A[c][0];
if(b && a * 1.0 / b < tmp) {
tmp = a * 1.0 / b, ans = i;
}
else if(b && a * 1.0 / b == tmp){
if(data[ans] < data[i])
ans = i;
}
}
printf("%d
", ans);
int m;
scanf("%d", &m);
while(m--){
scanf("%d %d", &c, &x0);
z = x0, a = b = 0;
for(int j = 20; j >= 0; --j){
//printf("c = %d j = %d f[c][j] = %d z = %d a[c][j] = %d b[c][j] = %d
", c, j, f[c][j], z, A[c][j], B[c][j]);
if(f[c][j] && z >= A[c][j] + B[c][j]){
a += A[c][j];
b += B[c][j];
z -= A[c][j] + B[c][j];
c = f[c][j];
}
}
if(A[c][0] <= z) a += A[c][0];
printf("%d %d
", a, b);
}
return 0;
}