1. 程式人生 > 其它 >【HDU 5550 Game Rooms】題解

【HDU 5550 Game Rooms】題解

題目連結

題目

Your company has just constructed a new skyscraper, but you just noticed a terrible problem: there is only space to put one game room on each floor! The game rooms have not been furnished yet, so you can still decide which ones should be for table tennis and which ones should be for pool. There must be at least one game room of each type in the building.

Luckily, you know who will work where in this building (everyone has picked out offices). You know that there will be Ti table tennis players and Pi pool players on each floor. Our goal is to minimize the sum of distances for each employee to their nearest game room. The distance is the difference in floor numbers: 0 if an employee is on the same floor as a game room of their desired type, 1 if the nearest game room of the desired type is exactly one floor above or below the employee, and so on.

計劃建設 N 層高的運動樓,每層樓要麼建游泳池,要麼建乒乓球室,只能二選一。
已知第 i 層有 \(T_i\) 個人打乒乓球,\(P_i\) 個人想游泳。
如果該層樓沒有對應的功能室,對應的人只能去最近的樓層運動。
單個人爬一層樓的額外運動量是 1,問最合理的設計下,滿足每個人的需求時,最少付出的額外運動量總和是多少。

\(N <= 4000,\ 0 <= T_i,P_i <= 10^{9}\)

思路

\(dp(i, k)\) 表示第 \(i\) 層修建設施 \(k\),且第 \(i+1\) 層修建另一種建築物,前 \(i\) 層的最小代價。

然後我們列舉一個樓層 \(j\)

,使 \([j+1, i]\) 層都修建建築 \(k\),然後我們再讓 \([j+1, i]\) 不是 \(k\) 的人去 \(j\)\(i+1\) 層去。

\[\Large dp(i, k)=\min_{j=1}^{i-1}dp(j, k)+go(j+1, i, k') \]

初始化我們假設前 \(i\) 層都修建建築 \(k\)

注意在轉移過程中我們就要統計答案,我們可以假設 \([i+1, n]\) 都修建建築 \(k'\)

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 4010
int n, m, i, j, k; 
int sum[N][2], dsm[N][2], dp[N][2]; 
int l, r, mid, x, ans, t, T; 

int goup(int l, int r, int k) // [l, r]-> r+1 
{
	return (sum[r][k]-sum[l-1][k])*(r+1)-(dsm[r][k]-dsm[l-1][k]); 
}

int godown(int l, int r, int k) // [l, r]->l-1
{
	return (dsm[r][k]-dsm[l-1][k])-(sum[r][k]-sum[l-1][k])*(l-1); 
}

int go(int l, int r, int k)
{
	mid=(l+r)>>1; 
	return godown(l, mid, k)+goup(mid+1, r, k); 
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	T=read(); 
	while(T--)
	{
		n=read(); 
		for(i=0; i<n*2; ++i)
		{
			x=read(); 
			sum[i/2+1][i&1]=sum[i/2][i&1]+x; 
			dsm[i/2+1][i&1]=dsm[i/2][i&1]+x*(i/2+1); 
		}
		ans=0x3f3f3f3f3f3f3f3f; 
		for(i=1; i<n; ++i)
		{
			dp[i][0]=goup(1, i, 1); 
			dp[i][1]=goup(1, i, 0); 
			for(j=1; j<i; ++j)
			{
				dp[i][0]=min(dp[i][0], dp[j][1]+go(j+1, i, 1)); 
				dp[i][1]=min(dp[i][1], dp[j][0]+go(j+1, i, 0)); 
			}
			ans=min(ans, dp[i][0]+godown(i+1, n, 0)); 
			ans=min(ans, dp[i][1]+godown(i+1, n, 1)); 
		}
		printf("Case #%lld: %lld\n", ++t, ans); 
	}
	return 0; 
}