95 计费法是华为云在许多场景下的网络带宽计费方法,即某个节点的费用通过一个计费周期内所有网络流量采样点的 95 分位点来计算。当拥有很多个可进行流量调度的节点时,问题就变得有趣起来了。作为降低成本的重要一环,华为云需要你聪明的脑袋使用各种奇技淫巧来把这个计费点摁下去。
但是对于小 A 来说并没有这个烦恼。小 A 只有一个可用节点,所有的流量都只能往上堆。虽然小 A 没有钱,但是他拥有重新划分计费区间的神奇能力。小 A 需要你的帮助。对于一个有 n 个网络采样点的时间区间,小 A 希望你将这个区间重新划分为 m 个非空区间,并最小化每段的分位点之和。
简短题意:
给一个长度为 n 的序列 a[1…n],将其分为 m 段(不可为空),使得每段的 95 分位点大小之和最小。
95 分位点:区间第 len−⌊0.05×len⌋ 小的数,len 表示区间长度(元素个数)。
Input
第一行一个整数 T,表示数据组数。(1≤T≤10)
对于每组数据:
第一行两个整数 n 和 m。(1≤m≤n≤100)
第二行 n 个整数,表示序列 a。(0≤a[i]≤1000)
Output
对于每组数据,输出一个整数,表示最小的 95 分位点大小之和。
Sample Input
2
5 2
777 96 114 920 206
5 5
804 253 746 267 487
Sample Output
1126
2557
题目重点是:
小 A 希望你将这个区间重新划分为 m 个非空区间,并最小化每段的分位点之和。
因此分为两步:
递推方程:
f[i][k]=min(f[i][k],f[j][k-1]+b[j+1][i]);
#include
using namespace std;
typedef unsigned long long ll;
const int maxn=1e2+10;
const ll INF=0x3f3f3f3f3f;
const int mod=998244353;
ll t;
ll n,m;
ll a[maxn];
ll f[maxn][maxn];
ll b[maxn][maxn];
ll c[100];
int calc(int l,int r){
int cnt=0;
for(int i=l;i<=r;i++){
c[++cnt]=a[i];
}
sort(c+1,c+1+cnt);
int id=(r-l+1)-(r-l+1)/20;
return c[id];
}
void solve(){
memset(f,INF,sizeof(f));
f[0][0]=0;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
b[i][j]=calc(i,j);
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
for(int k=1;k<=i;k++){
f[i][k]=min(f[i][k],f[j][k-1]+b[j+1][i]);
}
}
}
printf("%lld\n",f[n][m]);
}
int main(){
scanf("%lld",&t);
while(t--){
solve();
}
return 0;
}