登機

登機

題目鏈接:jzoj 5535

題目

HH是機場登機的執行經理。他的工作是優化登機流程。飛機上的座位有SS行,編號從11SS,每行有六個座位,標記爲AAFF

今天 有nn個乘客陸續登機,第ii名乘客的座位在第RiR_i行,則第ii名乘客的登機難度等於在他登機時坐在1..Ri11..R_i-1行的乘客的人數。
在這裏插入圖片描述
例如,如果有1010名乘客,他們的座位是6A6A4B4B2E2E5F5F2A2A3F3F1C1C10E10E8B8B5A5A,那麼他們的登機困難分別是000000220022,00777755,則難度總和爲2323

爲了降低登機難度,小HH想要將飛機座位劃分爲kk個區域。每一個區域必須是連續的行。劃分成kk個區域之後,乘客的登機順序不會改變,但是每個乘客的登機難度將只統計該乘客所在區域前面乘客的人數。

例如,在上面的例子中,如果我們把該平面分成兩個區域: 5105-10行和141-4行 ,然後在第一區域中的乘客的座位爲6A6A5F5F10E10E8B8B5A5A;在第二區域中的乘客的座位爲4B4B2E2E2A2A3F3F1C1C,這種情況下,登機難度綜合爲66

現在,小HH不知道該怎麼劃分這kk個區域,才能讓乘客的登機難度總和最少。

輸入

輸入文件第一行包含三個整數NNSSkk,下一行包含NN個整數RiR_i,輸入保證每一行座位由最多有66名乘客。

輸出

輸出文件包含一個整數,表示登機可能的最小登機難度。

樣例輸入

10 12 2
6 4 2 5 2 3 1 11 8 5

樣例輸出

6

數據範圍

40%40\%的數據,n<=100n<=100s<=100s<=100
100%100\%的數據,n<=1000n<=1000s<=1000s<=1000 , 1Ris1≤R_i≤s , k<=50k<=50 , k<=sk<=s

思路

這道題是一道dpdp

我們先通過前綴和求出第ii排人給第jj排人造成的登機難度和。(用b[i][j]b[i][j]表示)
接着,通過dpdp得出第ii排到第jj排爲一個區間時,這個區間的登機難度和。如果用f[i][j]f[i][j]表示,則動態轉移方程則爲:
f[i][j]=f[i][j1]+b[j][j]b[i1][j];f[i][j] = f[i][j - 1] + b[j][j] - b[i - 1][j];
最後,我們就可以再用dpdp求出答案了。設ans[i][j]ans[i][j]爲對於前ii排,把它劃分成jj個區間所最後需要的最小登機難度,那麼這個動態轉移方程就是:
ans[i][j]=min(ans[i][j],ans[l1][j1]+f[l][i]);ans[i][j] = min(ans[i][j], ans[l - 1][j - 1] + f[l][i]);
那麼最後我們只需要輸出ans[s][k]ans[s][k]就可以了。

代碼

#include<cstdio>
#include<cstring>
#define min(x, y) (x) < (y) ? (x) : (y)

using namespace std;

int n, s, k, a[1001], b[1001][1001], f[1001][1001], ans[1001][1001];

int main() {
//	freopen("board.in", "r", stdin);
//	freopen("board.out", "w", stdout);
	
	scanf("%d %d %d", &n, &s, &k);//讀入
	
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);//讀入
		for (int j = 1; j < i; j++)
			if (a[j] < a[i])
				b[a[j]][a[i]]++;//記錄某兩行之間產生的登機難度和
	}
	
	for (int i = 1; i <= s; i++)
		for (int j = 1; j <= s; j++)
			b[i][j] += b[i - 1][j];//前綴和
	
	for (int i = 1; i <= s; i++)
		for (int j = 1; j <= s; j++)
			f[i][j] = f[i][j - 1] + b[j][j] - b[i - 1][j];//dp
	
	memset(ans, 0x7f, sizeof(ans));//初始化
	ans[0][0] = 0;//初始化
	for (int i = 1; i <= s; i++)
		for (int j = 1; j <= k; j++)
			for (int l = j; l <= i; l++)//枚舉開始新區塊的位置
				ans[i][j] = min(ans[i][j], ans[l - 1][j - 1] + f[l][i]);//dp
	
	printf("%d", ans[s][k]);//輸出
	
//	fclose(stdin);
//	fclose(stdout);
	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章