Description
小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个区域,才能让乘客的登机难度总和最少。
Input
输入文件第一行包含三个整数N,S,和k,下一行包含n个整数(1≤Ri≤S),输入保证每一行座位由最多有6名乘客。
Output
输出文件包含一个整数,表示登机可能的最小登机难度。
Sample Input
10 12 2
6 4 2 5 2 3 1 11 8 5
Sample Output
6
Data Constraint
40%的数据,n<=100,s<=100
100%的数据,n<=1000,s<=1000, k<=50, k<=s
分析:很显然的一个dp,设f[i,k]为前i排,分成k个区域的答案。
f[i,k]=f[j,k-1]+sum(j+1,i)
这个和怎么求呢?
我们考虑每排的贡献,为这个人前面的人,以及这个人会先上飞机。很显然弄出一个S[n,m]表示坐在第n排的人,前m排的人对他的影响。对于区间[j+1,i],他的影响就是S[n,i]-S[n,j]{j+1<=n<=i}
其实这个也是一个和,可以用g[x,y]表示区间[x,y]的影响,有
g[x,y]=S[n,y]-S[n,x-1] (x<=n<=y)
所以,
g[x,y]=g[x,y-1]+S[y,y]-S[y,x-1]
于是用O(n^2)可得解。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 1002
#define K 53
#define inf 0x3f3f3f3f
using namespace std;
int n,s,k,x;
int sum[N][N],g[N][N];
int r[N];
int f[N][K];
int main()
{
freopen("board.in","r",stdin);
freopen("board.out","w",stdout);
scanf("%d%d%d",&n,&s,&k);
fo(i,1,n)
{
scanf("%d",&r[i]);
fo(j,1,i-1)
if (r[i]>r[j])
sum[r[i]][r[j]]++;
}
fo(i,0,N)
fo(j,0,K)
{
f[i][j]=inf;
}
fo(i,1,s)
fo(j,1,s)
{
sum[i][j]+=sum[i][j-1];
}
fo(i,1,s)
fo(j,i,s)
{
g[i][j]=g[i][j-1]+sum[j][j]-sum[j][i-1];
}
f[0][0]=0;
fo(i,1,s)
{
fo(j,1,k)
{
fo(l,0,i-1)
{
f[i][j]=min(f[i][j],f[l][j-1]+g[l+1][i]);
}
}
}
printf("%d",f[s][k]);
}