1. 程式人生 > >bzoj 1563 [NOI2009]詩人小G 決策單調性+dp

bzoj 1563 [NOI2009]詩人小G 決策單調性+dp

ref bit std online mes pac c++ () include

題面

題目傳送門

解法

可以得到一個顯然的dp方程

$\(f_i=min(f_j+(s_i-s_j+i-j-1-L)^p)\)

不妨把後面的東西看成\(w(j,i)\)

所以就變成\(f_i=min(f_j+w(j,i))\)

可以發現,這個式子滿足四邊形不等式

1D1D的四邊形不等式可以直接通過決策單調性來優化

轉移時註意邊界

時間復雜度:\(O(n\ log\ n)\)

代碼

#include <bits/stdc++.h>
#define LD long double
#define N 100010
using namespace std;
struct Node {
    int p, l, r;
} q[N];
int n, p, L, s[N], g[N];
LD f[N]; string st[N];
LD Pow(LD x, int y) {
    LD ret = 1;
    while (y) {
        if (y & 1) ret *= x;
        y >>= 1, x *= x;
    }
    return ret;
}
LD calc(int x, int y) {
    return f[y] + Pow(abs(s[x] - s[y] - 1 - L), p);
}
int solve(int p, int l, int r, int i) {
    int ans = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (calc(mid, p) < calc(mid, i)) l = mid + 1;
            else ans = mid, r = mid - 1;
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);
    int T; cin >> T; 
    while (T--) {
        cin >> n >> L >> p;
        for (int i = 1; i <= n; i++)
            cin >> st[i], s[i] = s[i - 1] + st[i].size() + 1;
        int h = 1, t = 1; q[t] = (Node) {0, 1, n};
        for (int i = 1; i <= n; i++) {
            while (h <= t && q[h].r < i) h++;
            f[i] = calc(i, q[h].p), g[i] = q[h].p;
            if (h > t || calc(n, q[t].p) > calc(n, i)) {
                while (h <= t && calc(q[t].l, q[t].p) > calc(q[t].l, i)) t--;
                if (h <= t) {
                    int x = solve(q[t].p, q[t].l, n, i);
                    q[t].r = x - 1, q[++t] = (Node) {i, x, n};
                } else q[++t] = (Node) {i, i, n};
            }
        }
        if (f[n] <= 1e18) cout << (long long)(f[n] + 0.5) << "\n";
            else cout << "Too hard to arrange\n";
        cout << "--------------------\n";
    }
    return 0;
}

bzoj 1563 [NOI2009]詩人小G 決策單調性+dp