标签:
题意:
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 }
Codeforces675E Trains and Statistic RMQ优化 dp+贪心
标签:
原文地址:http://www.cnblogs.com/honeycat/p/5590604.html