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;
}
凡所不能将我击倒的,都将使我更加强大