【前缀和】【DP】登机

登机流程优化

BeforeBeforeBefore thethethe texttexttext

莫名感觉自己有扣标的水分。。。

DescriptionDescriptionDescription

小H是机场登机的执行经理。他的工作是优化登机流程。飞机上的座位有S行,编号从1到s,每行有六个座位,标记为A到F。
今天 有n个乘客陆续登机,第i名乘客的座位在第Ri行,则第i名乘客的登机难度等于在他登机时坐在1…R(i-1)行的乘客的人数。
在这里插入图片描述
例如,如果有10名乘客,他们的座位是6A,4B,2E,5F,2A,3F,1C,10E,8B,5A,那么他们的登机困难分别是0,0,0,2,0,2,0,7,7,5,则难度总和为23 。
为了降低登机难度,小H想要将飞机座位划分为k个区域。每一个区域必须是连续的行。划分成k个区域之后,乘客的登机顺序不会改变,但是每个乘客的登机难度将只统计该乘客所在区域前面乘客的人数。
例如,在上面的例子中,如果我们把该平面分成两个区域: 5-10行和1-4行 ,然后在第一区域中的乘客的座位为6A,5F,10E,8B,5A;在第二区域中的乘客的座位为4B,2E,2A,3F,1C,这种情况下,登机难度综合为6。
现在,小H不知道该怎么划分这k个区域,才能让乘客的登机难度总和最少。

InputInputInput

输入文件第一行包含三个整数N,S,和k,下一行包含n个整数(1≤Ri≤S),输入保证每一行座位由最多有6名乘客。

OutputOutputOutput

输出文件包含一个整数,表示登机可能的最小登机难度。

SampleSampleSample InputInputInput

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

SampleSampleSample OutputOutputOutput

6

HintHintHint

数据范围
40%的数据,n<=100,s<=100
100%的数据,n<=1000,s<=1000, k<=50, k<=s

TrainTrainTrain ofofof ThoughtThoughtThought

设一个s[i][j]s[i][j]s[i][j]表示前i行的人对前j行的人造成的困扰值总和
设一个f[i][j]f[i][j]f[i][j]表示划分i到j的区域的困扰值总和
设一个ans[i][j]ans[i][j]ans[i][j]为前i个划分为j块的最小困扰值

CodeCodeCode

#include<cstdio> 
#include<cstring>
#include<iostream>
using namespace std;
int n,m,k,l[1005],s[1005][1005],f[1005][1005],ans[1005][1005];
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1; i<=n; ++i)
	{
		scanf("%d",&l[i]);
		for (int j=1; j<i; ++j)
		 if (l[j]<l[i])
		   s[l[j]][l[i]]++;//统计
	}
	memset(ans,0x7f,sizeof(ans));
	ans[0][0]=0;
	for (int i=1; i<=m; ++i)
	 for (int j=1; j<=m; ++j)
	    s[i][j]+=s[i-1][j];//前缀和
	for (int i=1; i<=m; ++i)
	 for (int j=1; j<=m; ++j)
	   f[i][j]=f[i][j-1]+s[j][j]-s[i-1][j];//计算区域内的值
	for (int i=1; i<=m; ++i)
	 for (int j=1; j<=k; ++j)
	   for (int q=j; q<=i; ++q)
	      ans[i][j]=min(ans[i][j],ans[q-1][j-1]+f[q][i]);//原本小还是现在划分的情况小
	printf("%d",ans[m][k]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值