思路:
贪心 + dp,O(n ^ 2);
先选出现次数最多的一定是最优解。
dp[i][j]表示前i位分成了m组的最优解。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<vi> vii;
typedef vector<ll> vll;
const int MAXN = 1e6 + 10;
const ll INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1.0);
int n, m, k;
vi p, sum;
vector<vll> dp;
bool cmp(int a, int b){
return a > b;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout << setprecision(4) << fixed;
int times;
cin >> times;
while(times--){
cin >> n >> m;
p.clear();
p.resize(n + 1);
for(int i = 1; i < (int)p.size(); i++)
cin >> p[i];
sort(p.begin() + 1, p.end(), cmp);
sum.clear();
sum.resize(p.size() + 1);
for(int i = 1; i < (int)p.size(); i++)
sum[i] = sum[i - 1] + p[i];
dp.clear();
dp.resize(p.size(), vll(m + 1));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= min(i, m); j++){
if(j == 1)
dp[i][j] = (ll)i * sum[i];
else{
ll res = INF * INF;
for(int t = i - 1; t >= max(1, j - 1); t--)
res = min(res, dp[t][j - 1] + (ll)i * (sum[i] - sum[t]));
dp[i][j] = res;
}
}
cout << (double)dp[n][m] / sum[n] << endl;
}
cerr << "execute time : " << (double)clock() / CLOCKS_PER_SEC << endl;
return 0;
}
未来可期。