zoukankan      html  css  js  c++  java
  • NOIP 2012 洛谷P1081 开车旅行

    Description:

    就是两个人开车,只能向东开。向东有n个城市,城市之间的距离为他们的高度差。A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市。如果车子开到底了或者车子开的路程已经超过了限制X就停。

    问你从一个点出发,最后A行驶的里程数和B行驶的里程数。

    倍增的妙用,这道题改变了我对NOIP的看法。让我对着书看了好久才看懂

    不过70分还是好拿的,就是预处理然后对每个询问$O(n)$ 模拟一遍。复杂度$O(nlog_{2}n+nm)$

    怎么预处理?就是找到一个城市$i$后离他最近的城市和次近的城市,分别为$gb[i]$,$ga[i]$,用平衡树(set)或者链表或者权值线段树实现

    满分在70分的基础上,倍增预处理,然后$O(log_{2}n)$回答每个询问

    对于第一个询问,枚举起点即可。

    接下来, $dp[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车到达的城市,1表示A,2表示B。

    $sta[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车A所行驶的路程,$stb[i][j][k]$表示$k$在$j$点出发,共开$2^i$天的车B所行驶的路程。

    边界和初值:$dp[0][j][0]=ga[j]$,$dp[0][j][1]=gb[j]$,$sta[0][j][0]=dist(j,ga[j])$,$stb[0][j][1]=dist(j,gb[j])$ 其他都为0

    转移看代码,特别注意的是因为$i=1$时,两人是换着开的,所以转移的时候k要去个反。而$i>1$的话,$2^i$天和$2^{i-1}$时开车的人是相同的故不用取反

    其他对着状态就能理解了把,就不写注释了。

     1 /*代码修改自李煜东霸霸,变量名是按照书上说法开的*/
     2 #include<bits/stdc++.h>
     3 using namespace std;
     4 const int N = 1e5 + 10;
     5 #define ll long long
     6 ll sta[22][N][2], stb[22][N][2], ansA, ansB, la, lb;
     7 int dp[22][N][2], n, m, ga[N], gb[N], h[N], i, t, ans;
     8 struct node{ int x, y;} ;
     9 set<node> s;
    10 set<node>::iterator it,lt,rt;
    11 int dist(int x, int y){ return abs(h[x] - h[y]); }
    12 bool cmp(int x, int y){    return dist(x, i) == dist(y, i) ? h[x] < h[y] : dist(x, i) < dist(y, i); }
    13 bool operator < (node a, node b){ return a.y < b.y; }
    14 void solve(int s, int X){
    15     la = lb = 0; int k = 0;
    16     for(int j = t; j >= 0; j--)
    17       if(dp[j][s][k] && sta[j][s][k] + stb[j][s][k] <= X){
    18           X -= (sta[j][s][k] + stb[j][s][k]);
    19           la += sta[j][s][k], lb += stb[j][s][k];
    20           if(j == 0) k ^= 1;
    21           s = dp[j][s][k];
    22       }
    23 }
    24 int main(){
    25     scanf("%d", &n);
    26     for(int i = 1; i <= n; i++) scanf("%d", &h[i]);
    27     for(i = n; i >= 1; i--){
    28         node tmp; tmp.x = i, tmp.y = h[i];
    29         int temp[10];
    30         s.insert(tmp); it = s.find(tmp);
    31         lt = it, rt = it, m = 0;
    32         if(lt != s.begin()) lt--, temp[++m] = lt -> x;
    33         if(lt != s.begin()) lt--, temp[++m] = lt -> x;
    34         if(rt++, rt != s.end()){
    35             temp[++m] = rt -> x;
    36             if(rt++, rt != s.end()) temp[++m] = rt -> x;
    37         }
    38         sort(temp + 1, temp + m + 1, cmp);
    39         if(m) gb[i] = temp[1];
    40         if(m > 1) ga[i] = temp[2];
    41     }
    42     t = log(n * 1.0) / log(2.0);
    43     for(i = 1; i <= n; i++){
    44         if(ga[i]) dp[0][i][0] = ga[i], sta[0][i][0] = dist(ga[i], i), stb[0][i][0] = 0;
    45         if(gb[i]) dp[0][i][1] = gb[i], stb[0][i][1] = dist(gb[i], i), sta[0][i][1] = 0;
    46     }
    47     for(i = 1; i <= t; i++)
    48       for(int j = 1; j <= n; j++)
    49         for(int k = 0; k < 2; k++){
    50             int l;
    51             if(i == 1) l = k ^ 1; else l = k;
    52             if(dp[i - 1][j][k]) dp[i][j][k] = dp[i - 1][dp[i - 1][j][k]][l];
    53             if(dp[i][j][k]){
    54                 sta[i][j][k] = sta[i - 1][j][k] + sta[i - 1][dp[i - 1][j][k]][l];
    55                 stb[i][j][k] = stb[i - 1][j][k] + stb[i - 1][dp[i - 1][j][k]][l];
    56             }
    57         }
    58     int X0;
    59     scanf("%d", &X0);  ansA = 1, ansB = 0;
    60     for(i = 1; i <= n; i++){
    61         solve(i, X0);
    62         if(!lb) la = 1;
    63         if(la * ansB < lb * ansA || (la * ansB == lb * ansA && h[i] > h[ans]))
    64           ansA = la, ansB = lb, ans = i;
    65     }
    66     printf("%d
    ", ans);
    67     scanf("%d", &m);
    68     int x, y;
    69     while(m--){
    70         scanf("%d%d", &x, &y);
    71         solve(x, y);
    72         printf("%lld %lld
    ", la, lb);
    73     }
    74     return 0;
    75 }
    View Code

     倍增优化DP就是一个划分状态+状态拼凑的过程

  • 相关阅读:
    android截屏
    生产者消费者 ProducerConsumer
    实现RunOnUiThread和RunOnUiThreadBlock
    快速断网恢复方法
    JFrame2
    JFrame
    圆角矩形shader
    [转]Apache commons 工具包应用
    转载 [Java]读取文件方法大全
    转:aop的学习
  • 原文地址:https://www.cnblogs.com/Rorshach/p/9280919.html
Copyright © 2011-2022 走看看