题目链接:https://www.luogu.org/problem/show?pid=1220
题解:
- 我们发现它关的路灯一定是一个连续的区间,而且关掉一个区间的灯时,这个人一定在区间的左端点和右端点,那么我们考虑可以拿区间DP做
- 用
f[i][j][0/1]
表示关掉
[i,j]
区间的灯时花费的最少的功耗,0/1表示人此时在左端/右端,那么只要求一个功率的前缀和就能
O(1)
地转移,
dp方程推一推就出来了
/*f[i][j][0]=min(
f[i+1][j][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[j]),
f[i+1][j][1]+(pos[j]-pos[i])*(sum[i]+sum[n]-sum[j])
)
f[i][j][1]=min(
f[i][j-1][0]+(pos[j]-pos[i])*(sum[i-1]+sum[n]-sum[j-1]),
f[i][j-1][1]+(pos[j]-pos[j-1])*(sum[i-1]+sum[n]-sum[j-1])
) */
//by sdfzchy
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=60;
int f[100][100][2],n,w[N],pos[N],c,sum[N];
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) scanf("%d%d",&pos[i],&w[i]),sum[i]=sum[i-1]+w[i];
memset(f,0x3f,sizeof(f));
f[c][c][0]=f[c][c][1]=0;
for(int i=c+1;i<=n;i++)
{
f[c][i][1]=f[c][i-1][1]+(pos[i]-pos[i-1])*(sum[n]-sum[i-1]+sum[c-1]);
f[c][i][0]=f[c][i][1]+(pos[i]-pos[c])*(sum[n]-sum[i]+sum[c-1]);
}
for(int i=c-1;i;i--)
{
f[i][c][0]=f[i+1][c][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[c]);
f[i][c][1]=f[i][c][0]+(pos[c]-pos[i])*(sum[i-1]+sum[n]-sum[c]);
}
for(int i=c-1;i;i--)
for(int j=c+1;j<=n;j++)
{
f[i][j][0]=min(f[i+1][j][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[j]),f[i+1][j][1]+(pos[j]-pos[i])*(sum[i]+sum[n]-sum[j]));
f[i][j][1]=min(f[i][j-1][0]+(pos[j]-pos[i])*(sum[i-1]+sum[n]-sum[j-1]),f[i][j-1][1]+(pos[j]-pos[j-1])*(sum[i-1]+sum[n]-sum[j-1]));
}
printf("%d\n",min(f[1][n][0],f[1][n][1]));
return 0;
}