zoukankan      html  css  js  c++  java
  • [NOIP2012] 开车旅行

    [NOIP2012] 开车旅行

    题目大意:在数轴上有(n)个不同高度的城市从西到东排列,定义(dis(i,j))(i)城市到(j)城市的(abs(h_i,h_j)),有两个人(A)(B)轮流开车从任意城市出发向东旅行,(A)一定是先开车的,他会选择去距离当前城市第二近的城市((dis)一样,去高度低的城市),走一定的里程,那么第二次(B)在开车,他会选择去距离当前的城市最近的城市((dis)一样,去高度低的城市),走一定的里程;如果对于(A,B)里程不够了,或者没有可以选的城市了,结束旅行.现在有两个询问

    1. 无论从哪个地方出发,给定里程数,求(A,B)开车里程的最小比值所在的旅行的出发地,如果有多个出发地的比值相同,取海拔高的
    2. 给定(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;
    }
    
  • 相关阅读:
    拓扑排序笔记
    Codeforces Round #683 (Div. 2, by Meet IT)(A->C)(构造,思维,贪心)
    Acwing 846. 树的重心(DFS枚举删除每一个点)
    Acwing 125. 耍杂技的牛(贪心)(从局部到全局)
    Acwing 802. 区间和(下标离散化+vector+二分)
    Acwing 799. 最长连续不重复子序列(双指针)
    Acwing 139. 回文子串的最大长度(前缀+后缀处理+哈希+二分)
    Linux shell 变量$#,$@,$0....的含义
    一双不锈钢筷子 的测试用例?
    OSI模型 TCP/IP模型 再整理
  • 原文地址:https://www.cnblogs.com/LMSH7/p/9605605.html
Copyright © 2011-2022 走看看