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

CF 1012C Dp

时间:2020-04-01 13:15:04      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:注意   res   room   one   uri   incr   const   ever   输出   

Welcome to Innopolis city. Throughout the whole year, Innopolis citizens suffer from everlasting city construction.

From the window in your room, you see the sequence of n hills, where i-th of them has height ai. The Innopolis administration wants to build some houses on the hills. However, for the sake of city appearance, a house can be only built on the hill, which is strictly higher than neighbouring hills (if they are present). For example, if the sequence of heights is 5, 4, 6, 2, then houses could be built on hills with heights 5 and 6 only.

The Innopolis administration has an excavator, that can decrease the height of an arbitrary hill by one in one hour. The excavator can only work on one hill at a time. It is allowed to decrease hills up to zero height, or even to negative values. Increasing height of any hill is impossible. The city administration wants to build k houses, so there must be at least k hills that satisfy the condition above. What is the minimum time required to adjust the hills to achieve the administration‘s plan?

However, the exact value of k is not yet determined, so could you please calculate answers for all k in range 技术图片? Here 技术图片 denotes n divided by two, rounded up.

分析

  先来分析状态的定义,首先输出的时候跟k有关,所以k一定要先占一个状态,山的数目也要占一个状态,因为不枚举每座山峰,就无法知道山峰的高度,那么状态可不可以只有i和j呢?显然也不可以,建房子的时候有高度限制。于是状态大致就有了,是一个三维的状态,dp[i][k][],那么剩下的那个状态怎么选呢,因为我们转移的时候只考虑了前边的i个,所以第i个建不建,只与第i-1个有关,i与i-1建房的情况有三种,都不建,i建,i-1建,i和i-1都建呢?请回去读题。所以定义dp[i][j][0..2],表示前i个山,建j个房子,0:i和i-1都不建,1:i建,2:i-1建时最小花费。接下来考虑状态转移,对于0的情况,就是dp[i-1][j][0]和

dp[i-1][j][2]的情况,前者是i-1和i-2都不建,后者是i-1不建,i-2建。这两种情况都是满足我们这个状态并且合起来正好能够填满这个状态。对于1的情况,i建了,那么i-1一定不能建,考虑i-2建还是不建,如果i-2建了,那么i-1的山峰就要满足比i-2和i都小,如果i-1比i-2要高,那么i-1就至少要被砍到i-2的高度-1的位置,即min(a[i-1],a[i-2]-1),如果这个数还比i高,那么它还要被砍,于是额外的代价就是h-(a[i]-1),所以总代价就是dp[i-1][j-1][2]+max(0,min(a[i-1],a[i-2]-1)-a[i]+1),再考虑i-2不建的情况,就是看i-1需不需要砍一刀,所以这个状态最后的转移方程就是:

  dp[i][j][1]=min(dp[i-1][j-1][0]+max(0,a[i-1]-a[i]+1),dp[i-1][j-1][2]+max(0,min(a[i-1],a[i-2]-1)-a[i]+1));

虽然有点长但是好好理解一下还是挺好懂得,最后就是2的情况了,如果i-1建了,那么就要保证i的高度低于i-1于是取a[i]-a[i-1]+1和0的最大值就行。最后可以小小的优化一下,状态转移的时候,i能且只能由i-1转移过来,所以第一维状态可以省略。

  最后就是初始化了,由于要求最小,所以最开始全部初始化为INF,初态dp[0][0],dp[1][1]均为0,稍微解释一下,建0座房子,显然叭,不花钱,建一个,也不花。

  tips::压维的话注意一点,转移的时候,要考虑转移顺序,先转移0,因为0受2的影响,再转移2,2受1的影响,最后是1,这样就可以避免用现阶段的东西来转移现阶段的东西,从而保证了转移的正确性。

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=2501;
 5 int dp[N][3],a[N<<1];
 6 int main(){
 7     int n;
 8     cin>>n;
 9     for(int i=1;i<=n;i++)
10         cin>>a[i];
11     memset(dp,0x3f,sizeof(dp));
12     dp[0][0]=dp[1][1]=0;
13     for(int i=2;i<=n;i++)
14         for(int j=i+1>>1;j;j--){
15             dp[j][0]=min(dp[j][0],dp[j][2]);
16             dp[j][2]=dp[j][1]+max(0,a[i]-a[i-1]+1);
17             dp[j][1]=min(dp[j-1][0]+max(0,a[i-1]-a[i]+1),dp[j-1][2]+max(0,min(a[i-1],a[i-2]-1)-a[i]+1));
18         }
19     for(int j=1;j<=n+1>>1;j++)
20         cout<<min(dp[j][0],min(dp[j][1],dp[j][2]))<<" ";
21 }

 

CF 1012C Dp

标签:注意   res   room   one   uri   incr   const   ever   输出   

原文地址:https://www.cnblogs.com/anyixing-fly/p/12611628.html

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