码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces675E Trains and Statistic RMQ优化 dp+贪心

时间:2016-06-16 13:17:04      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

题意:

a[i]表示从第i个车站买一张票可以坐到第[i+1,a[i]]个车站中任一个
p[i][j]表示从第i个车站到第j个车站的最少的票数,求∑p[i][j](1<=i<=n,i<j<=n)

思路:

构造dp[i]=∑p[i][j](i<j≤n)

贪心的想,每次从第i个车站买票坐到第m个车站(在[i+1,a[i]]中,a[m]最大),再往后坐车的选择是最优的,因为每次都能使在买相同的票数下走的最远除非目的地是在[i+1,a[i]]这个区间内,不需要走得远。

这样就可以分类讨论一下,假设所有路线都是先买到m站,那么dp[i]可以由dp[m]线性表示;而[i+1,m]区间内无论坐到哪里都是一张票,对结果没有影响;又因为[m,a[i]]这个区间只需要在i站买票就可以一次坐过去,而按之前的思路需要2张票,所以要把这个区间内多余的票数减掉。

so,dp[i] = dp[m] + (n - i){所有路线先买到m站} - (a[i] - m){多买票的区间}

 

问题解决了撒花~

 

技术分享
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn = 100005;
 5 int a[maxn],maxsum[maxn][20],n;
 6 vector<int> v[maxn];
 7 LL dp[maxn];
 8 void RMQ(int num) {
 9     for (int j=1; j<20; j++)
10         for (int i=1; i<=num; i++)
11             if (i + (1 << j) - 1 <= num)
12                 maxsum[i][j] = max(maxsum[i][j-1], maxsum[i+(1<<(j-1))][j-1]);
13 }
14 int main()
15 {
16     scanf("%d",&n);
17     for (int i=1; i<n; i++) {
18         scanf("%d",&a[i]);
19         v[a[i]].push_back(i);
20     }
21     for (int i=2; i<=n; i++) {
22         v[i].push_back(n);
23         sort(v[i].begin(), v[i].end());
24     }
25     for (int i=1; i<=n; i++)
26         maxsum[i][0] = a[i];
27     RMQ(n);
28     LL ans = 0;
29     dp[n] = 0;
30     for (int i=n-1; i>0; i--) {
31         int x = i, y = a[i];
32         int t = (int)(log(y - x + 1.0) / log(2.0));
33         int maxt = max(maxsum[x][t], maxsum[y-(1<<t)+1][t]);
34         int m = lower_bound(v[maxt].begin(), v[maxt].end(), i + 1) - v[maxt].begin();
35         m = v[maxt][m];
36         dp[i] = dp[m] + n - i - (a[i] - m);
37         ans += dp[i];
38     }
39     printf("%I64d\n", ans);
40     return 0;
41 }
View Code

 

Codeforces675E Trains and Statistic RMQ优化 dp+贪心

标签:

原文地址:http://www.cnblogs.com/honeycat/p/5590604.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!