[CSP-S模拟测试]:军训队列(DP+乱搞)
题目描述
有$n$名学生参加军训,军训的一大重要内容就是走队列,而一个队列的不规整程度是该队中最高的学生的身高与最矮的学生的身高差值的平方。
现在要将$n$名参加军训的学生重新分成$k$个队列,每个队列的人数不限,请求出所有队列的不规整程度之和的最小值。
输入格式
第一行两个整数$n,k$,表示学生人数和队列数。
第二行$n$个实数,表示每名学生的身高。身高范围在$140\sim 200cm$之间,保留两位小数。
输出格式
一个实数表示答案,保留$2$位小数。
样例
样例输入1:
3 2
170.00 180.00 168.00
样例输出1:
4.00
样例输入2:
5 2
170.00 180.00 168.00 140.59 199.99
样例输出2:
1023.36
数据范围与提示
题解
$50$分的$DP$应该都会打,问题就在于如何优化。
的确可以斜率优化,但是考虑身高的范围,也就是说最多有$6000$种不同的身高。
那么离散化一下不就$AC$啦?
再考虑另一种并不正确的算法,尽可能让平方差最大的一组最小;的确是错的,第二个样例都过不了,但是在数据范围比较大的时候很难被卡;再结合前面暴力$DP$即可拿到满分……
时间复杂度:$\Theta(6000\times 6000)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int n,k;
double h[100001];
double dp[100001][21];
double ans=1000000000.0;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%lf",&h[i]);
sort(h+1,h+n+1);
n=unique(h+1,h+n+1)-h-1;
for(int i=1;i<=n;i++)dp[i][1]=(h[i]-h[1])*(h[i]-h[1]);
for(int j=2;j<=k;j++)
for(int i=1;i<=n;i++)
{
dp[i][j]=10000000000.0;
for(int l=i;l>=j;l--)
dp[i][j]=min(dp[i][j],dp[l-1][j-1]+(h[i]-h[l])*(h[i]-h[l]));
}
printf("%.2lf",dp[n][min(n,k)]);
return 0;
}
rp++