传送门
解题思路
先明确一下题意,c指的是路灯的编号而不是位置。
然后根据贪心,在从点i去关点j的路灯时,所有经过的路灯都会随手关掉(不耗时间),所以我们可以确定,若i点和j点的路灯已经关闭,那么区间i...j的路灯已经全部关闭,而且关完后,最优策略一定是在点i处或者点j处。
这和上一题就很像了,用dp[i][j]表示把区间i...j的路灯全部关闭所有的最小电量。然后dp[i][j][0]表示关完后在i点时的最小电量,dp[i][j][1]表示关完后在j点时的最小电量。
最后想一下动态转移方程,dp[i][j][0]可以从dp[i+1][j][0]和dp[i+1][j][1]转移而来,dp[i][j][1]可以从dp[i][j-1][0]和dp[i][j-1][1]转移而来。
怎样计算呢?很显然是原来的dp值再加上关第i盏灯或第j盏灯要付出的代价。
代价怎么求?
我们很显然能作差求出距离(所用的时间),我们还需要知道到目前为止剩下的还未关的灯的功率和,因为已经关了的灯一定在某一区间内,然后又要求和,所以很自然地就想到了前缀和。
最后的最后,last but not least,重要的事情说三遍:
细节,细节,细节!
AC代码
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int n,a[105],w[105],dp[105][105][2],now,sum[105]; 5 int main() 6 { 7 cin>>n>>now; 8 memset(dp,0x3f,sizeof(dp)); 9 for(int i=1;i<=n;i++){ 10 cin>>a[i]>>w[i]; 11 sum[i]=sum[i-1]+w[i]; 12 } 13 dp[now][now][0]=dp[now][now][1]=0; 14 for(int len=2;len<=n;len++){ 15 for(int i=max(1,now-len+1);i<=min(now,n);i++){ 16 int j=i+len-1; 17 if(j>n) break; 18 dp[i][j][0]=min(dp[i+1][j][0]+(sum[i]+sum[n]-sum[j])*(a[i+1]-a[i]),dp[i+1][j][1]+(sum[i]+sum[n]-sum[j])*(a[j]-a[i])); 19 dp[i][j][1]=min(dp[i][j-1][0]+(sum[i-1]+sum[n]-sum[j-1])*(a[j]-a[i]),dp[i][j-1][1]+(sum[i-1]+sum[n]-sum[j-1])*(a[j]-a[j-1])); 20 } 21 } 22 cout<<min(dp[1][n][0],dp[1][n][1]); 23 return 0; 24 }