日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

bzoj4639 博士的选取器

發布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bzoj4639 博士的选取器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意

給出一個長度為n的正整數序列,要求把它劃分成若干個連續的區間,使得每個區間的數字之和都不超過給定的lim.最后的代價等于每個區間的最大值之和.求最小代價.n<=300000

分析

定義f[i]表示前i個數劃分成若干個區間的最小代價,一眼是個1D1D動態規劃,猜測有決策單調性,打表發現并沒有.然后也看不出什么很妙的性質.
感覺分治也許能做,推一推發現確實可以.定義solve(l,r)處理f[l...mid]到f[mid+1...r]的轉移,按照最大值在左邊/右邊分兩種情況處理,都可以線性解決.遞歸時要先solve(l,mid),然后處理[l,mid]到[mid+1,r]的轉移,再solve(mid+1,r).細節見代碼,不是很難寫.

#include<cstdio> #include<algorithm> using namespace std; const int maxn=300006; typedef long long ll; int n;ll lim; ll f[maxn]; ll pre[maxn],a[maxn]; ll Min[maxn],Max[maxn],mark[maxn]; void gmin(ll &a,ll b){if(a>b)a=b; } void solve(int l,int r){if(l==r)return;int mid=(l+r)>>1;solve(l,mid);Min[mid]=f[mid];Max[mid]=a[mid];for(int i=mid-1;i>=l;--i)Min[i]=min(Min[i+1],f[i]),Max[i]=max(Max[i+1],a[i]);Max[mid+1]=a[mid+1];for(int i=mid+2;i<=r;++i)Max[i]=max(Max[i-1],a[i]);int L=l,pt=mid+1;for(int i=mid+1;i<=r;++i){while(pre[i]-pre[L]>lim)L++;while((pt-1)>l&&Max[pt-1]<=Max[i])--pt;if(L>mid)break;gmin(f[i],Max[i]+Min[max(pt-1,L)]);}for(int i=mid+1;i<=r;++i)mark[i]=(1ll<<60);int R=r;pt=mid;for(int i=mid;i>l;--i){while(pre[R]-pre[i-1]>lim)R--;if(R<=mid)break;while(pt+1<=r&&Max[pt+1]<=Max[i])++pt;if(pt>mid){gmin(mark[min(pt,R)],f[i-1]+Max[i]);}}for(int i=r;i>=mid+1;--i){gmin(f[i],mark[i]);gmin(mark[i-1],mark[i]);}solve(mid+1,r); } int main(){scanf("%d%lld",&n,&lim);for(int i=1;i<=n;++i){scanf("%lld",&a[i]);pre[i]=pre[i-1]+a[i];}for(int i=1;i<=n;++i){if(pre[i]<=lim)f[i]=max(a[i],f[i-1]);else f[i]=1ll<<60;}solve(1,n);printf("%lld\n",f[n]);return 0; }

轉載于:https://www.cnblogs.com/liu-runda/p/6920650.html

總結

以上是生活随笔為你收集整理的bzoj4639 博士的选取器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。