GYM 100801J Journey to the “The World's Start”

来源:互联网 发布:centos mysql启动失败 编辑:程序博客网 时间:2024/05/16 09:11

Problem J. Journey to the “TheWorld’s Start”

Input file:

journey.in

Output file:

journey.out

Time limit:

2 seconds

Memory limit:

256 megabytes

Jerry Prince is the fourth grade studentand he goes to New-Lodnon to visit the most popular amusement park “The World’sStart”.

An airport he arrives at is next to thefirst stop of the metro line. This line hasnstops and “The World’s Start” is on the last of them. The metro ofNew-Lodnon is pretty fast so you may assume that you can get from a stop to thenext one in just one minute.

Jerry needs a travel card to use the metro. Each travel card has arange r and a price p. With a travel card of range r Jerry may travel no more thanrstops at once. Therefore, if Jerryenters metro at the stop i he shouldexit on one of the stops fromi r to i+ r inclusive. It takes diminutes to exit andreenter metro ati-th stop. There isno time required to enter the first stop or exit the last one.

Jerry is not very rich but he has some spare time, so he decided tobuy the cheapest travel card that will allow him to travel from the first metrostop to the last one in no more thantminutes.Input

The first line of the input file containstwo integers n and t — the number of stops and the maximumpossible time (2 ≤ n ≤ 50000; n− 1 ≤t ≤ 109).

The second line contains n − 1 integers pr — the prices of travel cards with ranger= 1...n− 1 (1 ≤ pr ≤ 100000)

The third line contains n −2 integers di — the numberof minutes required to reenter metro at stopi= 2...n − 1 (1 ≤ di ≤ 105). Output

Output a single integer p — the lowest possible price of onetravel card that allows Jerry to travel from the first to the last stop in nomore thantminutes.

Example

journey.in

 

journey.out

4 4

1 2 3

1 4

2

 


这好像是我碰到的第一道不太好描述题意的题目=。=


第一行输入两个数据 n, m。表示你去一个城市坐地铁,有n个地铁站,线性排布,要求你在m时间内从 1 坐到 n 。


接下来是 n - 1 个数字ma_i。表示第 i 种车票需要 ma_i 元


当你手持第 i 种车票的时候,你一次性最多可以坐 i 站。即加入你现在在 x 号站台,你可以一次性用 i 种车票到达 [x - i, x + i] 区间内的任意站台。


只能选择一种车票,可多次使用同一种车票。


再接下来是 n - 2 个数字,第 i 个数字表示加入你在i + 1 号站台下车需要额外花费多少时间,1 号和 n 号下车不需要花费时间。


从一站坐地铁到下一站需要花费 1 时间。


问在 m 时间内,你花费最少的钱能从 1 到达 n,输出钱数。


样例:

4 4

1 2 3

1 4

你选择第二种车票,先在二号站下车,再直达重点。 花费时间为 1 + 3

如果选择第一种车票,你必须在二号,三号都下车,花费时间 1 + 4 + 3




显然可以想到的就是我们没必要倒着坐车,所以我们路上必须花的时间为 n - 1。

然后贪心票价,当一个地铁票 a 可达范围小于地铁票 b 且价格高于地铁票b,那么地铁票 a 可以直接舍去。

这样我们就构造出了一个单调序列。


然后考虑对这个单调序列二分票价,然后DP



dp[i] 表示用 到达范围 为 range 的票到第 i 站花费的最少钱数。

dp[n] <= m - n + 1时返回 true


状态转移方程  dp[i] = min(dp[i - j]) + cost[i]  (1 <= i <= n, 1 <= j <= min(i - 1, range) )


如果直接算,时间复杂度是O(log * n * n)


于是我们需要快速求一个区间的最小值


用线段树或者分块优化快速求 min(dp[i - j])

这样我们就把一个n 变成了log 或者 sqrt(n)

线段树现场写 A 了,不懂分块会不会被 T。


然后好像有学长用最短路过了??

一脸懵逼

[cpp] view plain copy print?
  1. #include <bits/stdc++.h>  
  2. #define pb push_back  
  3. #define mp make_pair  
  4. #define LL long long  
  5. using namespace std;  
  6.   
  7. const int N = 100010;  
  8. const int INF = 0x3f3f3f3f;  
  9.   
  10. struct Tree  
  11. {  
  12.     int l;  
  13.     int r;  
  14.     int minn;  
  15. };  
  16.   
  17. struct Stack  
  18. {  
  19.     int r;  
  20.     int p;  
  21. };  
  22.   
  23. Tree tree[N * 4];  
  24. Stack st[N];  
  25. LL dp[N];  
  26. int cost[N];  
  27. int ans;  
  28. int len;  
  29. int n, m;  
  30. int w;  
  31. int li;  
  32.   
  33. void up(int x)  
  34. {  
  35.     tree[x].minn = min(tree[x << 1].minn, tree[x <<1 | 1].minn);  
  36. }  
  37.   
  38. void build(int x, int l, int r)  
  39. {  
  40.     tree[x].l = l;  
  41.     tree[x].r = r;  
  42.     tree[x].minn = INF;  
  43.     if(l == r){  
  44.         tree[x].minn = dp[l];  
  45.     }  
  46.     else{  
  47.         int mid = l + ((r - l) >> 1);  
  48.   
  49.         build(x << 1, l, mid);  
  50.         build(x << 1 | 1, mid + 1, r);  
  51.         up(x);  
  52.     }  
  53. }  
  54.   
  55. void update(int x, int p, int v)  
  56. {  
  57.     int ll = tree[x].l;  
  58.     int rr = tree[x].r;  
  59.   
  60.     if(ll == p && rr == p){  
  61.         tree[x].minn = v;  
  62.         dp[ll] = v;  
  63.     }  
  64.     else{  
  65.         int mid = ll + ((rr - ll) >> 1);  
  66.   
  67.         if(p <= mid){  
  68.             update(x << 1, p, v);  
  69.         }  
  70.         else{  
  71.             update(x << 1 | 1, p, v);  
  72.         }  
  73.         up(x);  
  74.     }  
  75. }  
  76.   
  77.   
  78. void query(int x, int l, int r)  
  79. {  
  80.     int ll = tree[x].l;  
  81.     int rr = tree[x].r;  
  82.   
  83.     if(ll == l && rr == r){  
  84.         if(tree[x].minn < ans){  
  85.             ans = tree[x].minn;  
  86.         }  
  87.   
  88.         ans = min(ans, tree[x].minn);  
  89.         return;  
  90.     }  
  91.     else{  
  92.         int ans = INF;  
  93.         int mid = ll + ((rr - ll) >> 1);  
  94.   
  95.         if(l <= mid){  
  96.             query(x << 1, l, min(r, mid));  
  97.         }  
  98.         if(r > mid){  
  99.             query(x << 1 | 1, max(mid + 1, l), r);  
  100.         }  
  101.         up(x);  
  102.     }  
  103. }  
  104.   
  105. bool check(int mid)  
  106. {  
  107.     memset(dp, 0, sizeof(dp));  
  108.     dp[1] = 0;  
  109.     build(1, 1, n);  
  110.     for(int i = 2; i <= n; i ++){  
  111.         ans = INF;  
  112.         query(1, max(1, i - mid), i - 1);///查询  
  113.         update(1, i, ans + cost[i]);///更新 dp  
  114.     }  
  115.     if(dp[n] > li){///li = m - n + 1;  
  116.         return false;  
  117.     }  
  118.     else{  
  119.         return true;  
  120.     }  
  121. }  
  122.   
  123. int main()  
  124. {  
  125.     int l, r;  
  126.     int right;  
  127.   
  128.     while(scanf("%d%d", &n, &m) == 2){  
  129.         len = 0;  
  130.         li = m - n + 1;  
  131.         memset(cost, 0, sizeof(cost));  
  132.   
  133.         scanf("%d", &w);  
  134.         st[len].r = 1;  
  135.         st[len].p = w;  
  136.         len ++;  
  137.         for(int i = 2; i < n; i ++){  
  138.             scanf("%d", &w);  
  139.             while(w <= st[len - 1].p && len){///构造单调序列  
  140.                 len --;  
  141.             }  
  142.             st[len].r = i;  
  143.             st[len].p = w;  
  144.             len ++;  
  145.         }  
  146.         for(int i = 2; i < n; i ++){  
  147.             scanf("%d", &cost[i]);  
  148.         }  
  149.         l = 1;  
  150.         r = len;  
  151.         while(l <= r){  
  152.             int mid = l + ((r - l) >> 1);  
  153.             int t = st[mid - 1].r;  
  154.   
  155.             if(check(t)){  
  156.                 r = mid - 1;  
  157.             }  
  158.             else{  
  159.                 l = mid + 1;  
  160.             }  
  161.         }  
  162.   
  163.         printf("%d\n", st[l - 1].p);  
  164.     }  
  165.   
  166.     return 0;