HDU 6606 Distribution of books — 2019第三場杭電多校 1004題

題意

大概說一下我理解的題意。。。

給你一個長度爲nn的序列,你可以隨意拋棄一些後綴數字,但必須保證序列至少包含kk個數字。

問將這個序列分成連續kk段後,問段的權值和最大值最小爲多少?

思路

二分,dp驗證,線段樹優化

二分答案,dp[i]dp[i]表示前ii個數能分成多少段

轉移:dp[i]=max(dp[j]+1)[sum[i]sum[j]x]dp[i] = \sum_{max}(dp[j]+1)[sum[i]-sum[j]\le x]

權值線段樹維護前綴和值對應的最大dpdp值,支持單點更新,區間查詢即可。


比賽時最初在想dpdp,因爲之前剛做過HDU - 1024這個最大mm子段和,然後自閉了好久不會優化複雜度。。

後來隊友說了句二分,感覺好有道理。。。。

經過一段時間的自閉,感覺好像知道怎麼寫了,想到了dp驗證,線段樹優化。。。but我沒想到權值線段樹,我想成了每個位置維護一個前綴和值和dp權值。。。。然後gg了,比賽代碼如下(不過我當時dp寫法不一樣,思路差不多

在這裏插入圖片描述

AC_Code

vector<LL> vs;
int ok(LL x) {
    vs.eb(-1e18);
    for(int i = 1; i <= n; ++i) {
        res[i] = res[i-1] + ar[i];
        vs.eb(res[i]), vs.eb(res[i] - x);
    }
    my_unique(vs);
    build(1, vs.size(), 1);
    int flag = 0;
    for(int i = 1; i <= n; ++i) {
        if(res[i] <= x) dp[i] = 1;
        else dp[i] = 0;
        int tmp = lower_bound(all(vs), res[i]) - vs.begin();
        int las = lower_bound(all(vs), res[i] - x) - vs.begin();
        int ret = query(las, vs.size(), 1, vs.size(), 1);
        if(ret) dp[i] = big(ret + 1, dp[i]);
        update(tmp, dp[i], 1, vs.size(), 1);
        flag = max(flag, dp[i]);
    }
    vs.clear();
    return flag >= k;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章