HZOJ1324の暗い雪

解決

まず、なおリード質問、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();
}

おすすめ

転載: www.cnblogs.com/FlySakura/p/11845200.html