解決
まず、なおリード質問、2つのセットに分けではなく、連続する2つのブロックに分割
各プログラムは、バイナリツリーの各ノードは、集合を表す二分木とみなすことができるので
、ことを次の最もK内悪い状況下で回答を依頼バイナリツリーを表す深さがKを超えない
各場合は、すべてのリーフノードの加重経路長である対応するバイナリツリーの加重経路長である確率よう
確率で割った値合計(固定値)
、この問題はに翻訳ます
いくつかの数、バイナリツリーを構築し、各リーフノードは、kの深さを超えることができないバイナリツリーの数を表すようにバイナリツリーの最小加重経路長
まず、どのように解無しの状況を判断するには?バイナリツリーは完全なバイナリツリーがある場合は、リーフノード番号は、まだ<nは、必ずしもではない解決策は何がある
今、答えを見つけるためにどのように考慮されていません
-------------------- -------------------------------------------------- ----------
最小加重経路の長さ?このような場合にはk = N、ハフマン木である場合には
その\(K <= \ N-) 、あなたはハフマン使用することはできません
私たちは、ツリー内の子リーフノードは、pの合計値がソートされ表した後に連続間隔、最適解は、である必要があり
、この時間間隔はDPできるように
\ [F [D] [I 1] [I] [K] + F [D - ] [J] =分(F [D - 1] [K + 1]〜[J] + SUM [J] - 。SUM [I - 1]、F [D] [I] [J])\]
\(F [D] [I]、[J] \ )この範囲がjに、iの最適値を検討する際に、現在の深さdを表し、
ここで実際に使用すると、事前に計算コストの考え方
私たちはどのくらいの深さ、特にすべての特定のポイントを知っているが、毎回私たちはありませんので、分割、すべての点iがjにあるそのような合計値を増加させるルートが増大する距離は、であることを\(SUM(P [X])は、(i <= X <= J)
\)------- -------------------------------------------------- ---------------------
しかし、この複雑です\(O(N ^ 4) \) とすぎない
(実際には、一定に背面に繰り返し呼び出さオプティマイザが、寸法DP、すなわち程度であれば\(F [I] [J ] [D] \ )となる\(F [D] [I]、[J] \)上に生きることができる
HZOJ)------------------------ -------------------------------------------------- ----------------------------
プレイテーブル(またはプッシュ柿)を見つけることができ、実際にはDPの伝達方程式は、2次元DPの決定を満たします単調性
(この式が実際に追加された砂利外部組み合わせ深さ寸法のみ)
を最適化することができる四角形DP転送不等式
複雑\(O(N ^ 3) \)
最適化DP四辺形不平等
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 400 + 10;
const int INF = 0x3f3f3f3f3f3f3f3f;
int n, q, a[MAXN];
int gcd(int x, int y) {
if (y == 0)
return x;
return gcd(y, x % y);
}
inline void init(void) {
scanf("%lld%lld", &n, &q);
for (register int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
}
int f[MAXN][MAXN][MAXN], sum[MAXN], loc[MAXN][MAXN];
inline void DP_init(void) {
sort(a + 1, a + n + 1);
for (register int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
for (register int i = 1; i <= n; ++i) {
for (register int j = 1; j <= n; ++j) {
if (i == j)
f[i][j][0] = 0;
else
f[i][j][0] = 1e18;
}
}
}
int ans;
inline void DP(void) {
for (register int d = 1; d <= q; ++d) {
for (register int len = 2; len <= n; ++len) {
for (register int i = 1; i <= n; ++i) loc[i][i] = i;
for (register int i = 1; i + len - 1 <= n; ++i) {
int j = i + len - 1;
f[i][j][d] = 1e18;
int now, p;
for (register int k = loc[i][j - 1]; k <= loc[i + 1][j]; ++k) {
now = f[i][k][d - 1] + f[k + 1][j][d - 1] + sum[j] - sum[i - 1];
if (f[i][j][d] > now) {
f[i][j][d] = now;
p = k;
}
loc[i][j] = p;
}
}
}
}
}
inline void work(void) {
if (q <= 9 && (1 << q) < n) {
printf("-1");
return;
}
DP_init();
DP();
ans = f[1][n][q];
printf("%lld/%lld", ans / gcd(ans, sum[n]), sum[n] / gcd(ans, sum[n]));
}
signed main() {
freopen("snow.in", "r", stdin);
freopen("snow.out", "w", stdout);
init();
work();
}
正常範囲DP
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 400 + 10;
const int INF = 0x3f3f3f3f3f3f3f3f;
int n, q, a[MAXN];
int gcd(int x, int y) {
if (y == 0)
return x;
return gcd(y, x % y);
}
inline void init(void) {
scanf("%lld%lld", &n, &q);
for (register int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
}
int f[MAXN][MAXN][MAXN], sum[MAXN];
inline void DP_init(void) {
sort(a + 1, a + n + 1);
for (register int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
for (register int i = 1; i <= n; ++i) {
for (register int j = 1; j <= n; ++j) {
if (i == j)
f[0][i][j] = 0;
else
f[0][i][j] = 1e18;
}
}
}
int ans;
inline void DP(void) {
for (register int d = 1; d <= q; ++d) {
for (register int len = 2; len <= n; ++len) {
for (register int i = 1; i + len - 1 <= n; ++i) {
int j = i + len - 1;
f[d][i][j] = 1e18;
for (register int k = i; k < j; ++k)
f[d][i][j] = min(f[d - 1][i][k] + f[d - 1][k + 1][j] + sum[j] - sum[i - 1], f[d][i][j]);
}
}
}
}
inline void work(void) {
if (q <= 9 && (1 << q) < n) {
printf("-1");
return;
}
DP_init();
DP();
ans = f[q][1][n];
printf("%lld/%lld", ans / gcd(ans, sum[n]), sum[n] / gcd(ans, sum[n]));
}
signed main() {
freopen("snow.in", "r", stdin);
freopen("snow.out", "w", stdout);
init();
work();
}