hdu5550 Game Rooms (动态规划)

4 篇文章 0 订阅
4 篇文章 0 订阅

表示制杖,参考了一下别人的题解,做完发现自己整个人都不好了,竟然没有发现这么弱的dp方程,(我不知怎么的,一开始居然想了一个n^3的dp方程)

设dp[i][s]表示计算到第i个且将其放在该段的最后一个,这一段全为s(0和1分别表示两种运动)

那么dp方程就是dp[i][s] = min{dp[j][s^1] + valueSum(j+1, i)},  j < i

valueSum(i, j)表示[i, j]区间内的员工到最近运动室的距离和

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 4005;
const int INF = 0x3f3f3f3f;
int n;
long long a[2][MAXN], sum[2][MAXN], value[2][MAXN], dp[MAXN][2];

long long leftCal(int l, int r, int s)
{
	long long x = value[s][r] - value[s][l-1];
	long long y = sum[s][r] - sum[s][l-1];
	return abs(x - y * (l - 1));
}

long long rightCal(int l, int r, int s)
{
	long long x = value[s][r] - value[s][l-1];
	long long y = sum[s][r] - sum[s][l-1];
	return abs(x - y * (r + 1));
}

long long areaDist(int l, int r, int s)
{
	if (l == 1) return rightCal(l, r, s);
	else if (r == n) return leftCal(l, r, s);
	else
	{
		int mid = (l + r) >> 1;
		return leftCal(l, mid, s) + rightCal(mid + 1, r, s);
	}
}

int main()
{
	int T; scanf("%d", &T);
	for (int kk = 1; kk <= T; kk++)
	{
		//input
		scanf("%d", &n);
		sum[0][0] = sum[1][0] = 0LL;
		value[0][0] = value[1][0] = 0LL;
		for (int i = 1; i <= n; i++)
		{
			scanf("%lld%lld", &a[0][i], &a[1][i]);
			sum[0][i] = sum[0][i-1] + a[0][i];
			sum[1][i] = sum[1][i-1] + a[1][i];
			value[0][i] = value[0][i-1] + a[0][i] * i;
			value[1][i] = value[1][i-1] + a[1][i] * i;
		}

		//initialize
		memset(dp, INF, sizeof(dp));
		for (int i = 1; i < n; i++)
		{
			for (int s = 0; s <= 1; s++)
				dp[i][s] = areaDist(1, i, s);
		}

		//dp
		for (int i = 1; i <= n; i++)
		{
			for (int s = 0; s <= 1; s++)
			{
				for (int j = 1; j < i; j++)
					dp[i][s] = min(dp[i][s], dp[j][s^1] + areaDist(j + 1, i, s));
			}
		}

		//output
		printf("Case #%d: %lld\n", kk, min(dp[n][0], dp[n][1]));
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值