【洛谷P1220】关路灯

题目有点难描述,内容请直接看原题。。

题解:
可以发现人在关路灯时无论走什么样的路径,从宏观上来看被关的灯总是构成一段包含初始点的连续区间。比如要关掉下标为 l (l < st)的灯,则一定要先关掉下标为 l+1 的灯,可以发现这应该是一个区间dp的题目。有了区间之外,还要记录的信息是对于区间 [l,r],老张在区间的哪个端点处,因此 dp[l][r][0/1] 表示区间 [l,r] 内的路灯已经都被关闭,且老张在左端点/右端点处的最小功率消耗是多少,转移方程在代码中给出,时间复杂度为 (O(n^2))

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=51;
typedef long long LL;

int n,st;
LL pos[maxn],w[maxn],sum[maxn];
LL dp[maxn][maxn][2];// 0 -> left 1 -> right

void read_and_parse(){
	scanf("%d%d",&n,&st);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&pos[i],&w[i]);
		sum[i]=sum[i-1]+w[i];
	}
}
void solve(){
	memset(dp,0x3f,sizeof(dp));
	dp[st][st][0]=dp[st][st][1]=0;
	for(int len=1;len<=n;len++){
		for(int i=0;i<=min(len,st-1);i++){
			int l=st-i,r=st+len-i;
			if(r>n)continue;
			dp[l][r][0]=min(dp[l+1][r][0]+(pos[l+1]-pos[l])*(sum[l]+sum[n]-sum[r]),dp[l+1][r][1]+(pos[r]-pos[l])*(sum[l]+sum[n]-sum[r]));
			dp[l][r][1]=min(dp[l][r-1][0]+(pos[r]-pos[l])*(sum[l-1]+sum[n]-sum[r-1]),dp[l][r-1][1]+(pos[r]-pos[r-1])*(sum[l-1]+sum[n]-sum[r-1]));
		}
	}
	printf("%lld
",min(dp[1][n][0],dp[1][n][1]));
}
int main(){
	read_and_parse();
	solve();
	return 0;
}
原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10946478.html