P1220 关路灯

题目链接

点我跳转

题目大意

共有 N 盏灯,第 \(i\) 盏灯的位置为 \(pi\)(单位 \(m\)),功率为 \(si\)

一开始所有灯都是亮的,且第 \(i\) 盏灯每亮一秒钟,就会消耗 \(si\) 的电量

现你位于第 \(c\) 盏灯的位置 , 你需要关闭所有的灯,问关闭所有灯需要消耗的最少电量为多少

( 你的行走速度为 \(1m/s\) )

解题思路

关完一个区间内的灯时 , 你必然在区间的左端点或者右端点

于是可以定义:

\(dp[l][r][0]\) 已关完区间 \([L , R]\) 内的灯 , 且最后一次关的灯在区间左端点

\(dp[l][r][1]\) 已关完区间 \([L , R]\) 内的灯 , 且最后一次关的灯在区间右端点

不难得到 :

\(dp[l][r][0]\) 可以由 \(dp[l + 1][r][0] , dp[l + 1][r][1]\) 转移得到

\(dp[l][r][1]\) 可以由 \(dp[l][r - 1][0] , dp[l][r - 1][1]\) 转移得到

转移的过程中 , 消耗的电量为 (总功率减去 - 已关点灯的功率) * 行走的距离

"已关点灯的功率"和"行走的距离"可以用前缀和维护

AC_Code

#include<bits/stdc++.h>
 
using namespace std;

const int M = 5e1 + 10;

struct node{
	int p , w , id;
	bool operator < (const node & b) const{
		return p < b.p;
	}
}a[M];

int sum1[M] , sum2[M] , dp[M][M][2];

int get1(int l , int r){
	return sum1[r] - sum1[l];
}

int get2(int l , int r){
	return sum2[r] - sum2[l - 1];
}

signed main()
{
	int n , c , tot = 0;
		
	cin >> n >> c;
	
	for(int i = 1 ; i <= n ; i ++) cin >> a[i].p >> a[i].w , a[i].id = i , tot += a[i].w;	

	sort(a + 1 , a + 1 + n);
	
	memset(dp , 0x3f , sizeof(dp));
	
	for(int i = 1 ; i <= n ; i ++) if(a[i].id == c) dp[i][i][0] = dp[i][i][1] = 0;
	
	for(int i = 1 ; i <= n ; i ++) sum1[i] = sum1[i - 1] + a[i].p - a[i - 1].p , sum2[i] = sum2[i - 1] + a[i].w;
	
	for(int len = 2 ; len <= n ; len ++)
	{
		for(int l = 1 ; l + len - 1 <= n ; l ++)
		{
			int r = l + len - 1;
			
			dp[l][r][0] = min(dp[l][r][0] , min(dp[l + 1][r][0] + get1(l , l + 1) * (tot - get2(l + 1 , r)) , 
							  					dp[l + 1][r][1] + get1(l , r) * (tot - get2(l + 1 , r))));
			dp[l][r][1] = min(dp[l][r][1] , min(dp[l][r - 1][0] + get1(l , r) * (tot - get2(l , r - 1)) , 
							  					dp[l][r - 1][1] + get1(r - 1 , r) * (tot - get2(l , r - 1))));
		}
	}
	
	cout << min(dp[1][n][0] , dp[1][n][1]) << '\n';
	
	return 0;
}
posted @ 2021-02-08 15:16  GsjzTle  阅读(85)  评论(0编辑  收藏  举报