CDQ 85pts 求助

P4655 [CEOI2017] Building Bridges

CloudWings @ 2023-12-09 18:13:42

/*
 * Date: 01/12/23 13:51
 * Time Spent: 1:48:14
 * Solution:
     1. dp[i] = min{dp[j] + (h[i]-h[j])^2 + w[i-1] - w[j]}
        dp[i] = min{dp[j] + h[i]^2-h[i]*h[j]+h[j]^2 + w[i-1] - w[j]}
            dp[i] - (h[i]*h[i] + w[i-1]) = dp[j] - w[j] + h[j]*h[j] - 2*h[i]*h[j]
            ~~~~~~~~~~~~~b~~~~~~~~~~~~~~   ~~~~~~~~~~~~y~~~~~~~~~~~   ~~~k~~ ~x~
        <=> y = k*x + b
 * Summhry:
     1. RAW55 没有跟自己取 min。。。
     2. 好像终于把斜率优化理解透了(好耶!
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// #define int long long
#define double long double
const int N = 1e5 + 5;
const ll inf = 1e18;
int n, h[N], st[N]; ll w[N], dp[N];
struct node {
    ll x, y, id;
    void upd (ll _dp) {
        x = h[id];
        y = _dp - w[id] + 1ll*h[id]*h[id];
    }
} a[N], tmp[N];
double slope (int p, int q) {
    if (a[q].x == a[p].x) return a[p].y > a[p].y ? -1e20 : 1e20;
    return (double)(a[q].y - a[p].y) / (a[q].x - a[p].x);
}
ll slope (int p) {
    return 2ll*h[a[p].id];
}
void CDQ (int l, int r) {
    if (l == r) return a[l].upd(dp[a[l].id]);
    int mid = l + r >> 1;
    stable_partition(a+l, a+r+1, [&](node p){ return p.id <= mid; });
    CDQ(l, mid);
    st[0] = 0;
    // printf("[%d,%d]\n", l, r);
    for (int i = l; i <= mid; i++) {
        while (st[0] >= 2 && slope(st[st[0]-1], st[st[0]]) >= slope(st[st[0]-1], i)) st[0]--;
        st[++st[0]] = i;
    }
    int t = 1;  // !
    for (int k = mid+1; k <= r; k++) {
        while (t < st[0] && slope(st[t], st[t+1]) < slope(k)) t++;
        // int i = a[k].id, j = a[st[t]].id;  // Both OK
        // dp[i] = min(dp[i], dp[j] + 1ll*(h[i]-h[j])*(h[i]-h[j]) + w[i-1] - w[j]);
        int i = a[k].id, j = st[t];
        dp[i] = min(dp[i], a[j].y - slope(k)*a[j].x + (1ll*h[i]*h[i] + w[i-1]));
    }
    CDQ(mid+1, r);
    inplace_merge(a+l, a+mid+1, a+r+1, [&](node p, node q){ return p.x < q.x; });
    // inplace_merge(a+l, a+mid+1, a+r+1, [&](node p, node q){ return p.x ^ q.x ? p.x < q.x : p.y > q.y; });
}
signed main () {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> h[i];
    for (int i = 1; i <= n; i++) cin >> w[i], w[i] += w[i-1];
    for (int i = 1; i <= n; i++) a[i].id = i, a[i].upd(dp[i]=inf);
    a[1].upd(dp[1]=0);
    stable_sort(a+1, a+n+1, [&](node p, node q){ return h[p.id] < h[q.id]; });
    CDQ(1, n);
    cout << dp[n];
    return 0;
}

Record

问题好像是跟 CDQ 最后归并的时候有关。

如果把:

inplace_merge(a+l, a+mid+1, a+r+1, [&](node p, node q){ return p.x < q.x; });

改成:

inplace_merge(a+l, a+mid+1, a+r+1, [&](node p, node q){ return p.x <= q.x; });

就只有 80pts 了 QAQ


by Mellow_Yellow @ 2023-12-09 18:37:53

@CloudWings cmp比较不要用<=,会RE/出现其他错误。


by CloudWings @ 2023-12-09 18:48:33

@Mellow_Yellow Er. 但是它还是 WA 的啊 QAQ


by Mugino_Shizuri @ 2023-12-09 21:04:47

@CloudWings 实际上,若sort的比较函数如果出现正比较和反比较都为true,则可能出现意想不到的结果。


by CloudWings @ 2023-12-10 08:07:14

@Mellow_Yellow @liyujiang

thx.

现在 A 了(虽然不是 cmp 挂了,而是 slope 在特判 x 相等的时候写挂了((


|