1. 程式人生 > >「長樂集訓 2017 Day10」劃分序列 (二分 dp)

「長樂集訓 2017 Day10」劃分序列 (二分 dp)

color -html math != mes 序列 spa cto html

「長樂集訓 2017 Day10」劃分序列

題目描述

給定一個長度為 n nn 的序列 Ai A_iA?i??,現在要求把這個序列分成恰好 K KK 段,(每一段是一個連續子序列,且每個元素恰好屬於一段),並且每段至少有一個元素,使得和最大的那一段最小。

請你求出這個最小值。

輸入格式

第一行兩個整數 n,K n, Kn,K,意義見題目描述。
接下來一行 n nn 個整數表示序列 Ai A_iA?i??。

輸出格式

僅一行一個整數表示答案。

樣例

樣例輸入

9 4
1 1 1 3 2 2 1 3 1

樣例輸出

5

數據範圍與提示

20% 20 \%20% 的數據,n≤100 n \leq 100n100
另有 20% 20 \%20% 的數據,Ai≥0 A_i \geq 0A?i??0
另有 20% 20 \%20% 的數據,Ai≤0 A_i \leq 0A?i??0
另有 20% 20 \%20% 的數據,K≤10 K \leq 10K10
100% 100 \%100% 的數據,1≤K≤n≤5×104,∣Ai∣≤3×104 1 \leq K \leq n \leq 5 \times 10 ^ 4, |A_i| \leq 3 \times 10 ^ 41Kn5×10?4??,A?i??3×10?4??

【題意】給一個序列 有正有負 要求恰好分成k份,使得和最大的那一份最小。

【分析】考慮二分答案,然後對於這個答案判斷他的可行性。如果一段序列最大的那份小於等於x,且最少可分為 L 份,最多可分為 R 份,

則他一定能分為res份,L<=res<=R,那我們dp求L,R,對於序列中某一段可表示為,sum[i]-sum[j]<=mid,sum[j]>=sum[i]-mid,那麽dp[i]可由

dp[j]得到,j<i且sum[j]>=sum[i]-mid,那麽我們可以樹狀數組維護最小/最大值。

#include <bits/stdc++.h>
#define
inf 0x3f3f3f3f #define met(a,b) memset(a,b,sizeof a) #define pb push_back #define mp make_pair #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define inf 0x3f3f3f3f using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 5e4+50;; const int M = 255; const int mod = 998244353; const int mo=123; const double pi= acos(-1.0); typedef pair<int,int>pii; typedef pair<ll,int>P; int n,k,sz; int a[N],mn[N],mx[N]; int sum[N],pos[N],p[N]; vector<pii>vec; void updmn(int x,int v) { for(;x;x-=x&-x) mn[x]=min(mn[x],v); } int getmn(int x) { int sum=inf; for(;x<=n;x+=x&-x) sum=min(sum,mn[x]); return sum; } void updmx(int x,int v) { for(;x;x-=x&-x) mx[x]=max(mx[x],v); } int getmx(int x) { int sum=-inf; for(;x<=n;x+=x&-x) sum=max(sum,mx[x]); return sum; } bool check(ll x){ for(int i=0,j=0;i<vec.size();i++){ while(j<vec.size()&&vec[j].first<vec[i].first-x)j++; pos[vec[i].second]=j+1; } for(int i=0;i<N;i++)mn[i]=inf,mx[i]=-inf; int l,r; ll res=0; for(int i=1;i<=n;i++){ res+=a[i]; int maxn=getmx(pos[i]); int minn=getmn(pos[i]); if(maxn!=-inf)maxn++; else { if(res<=x)maxn=1; } if(minn!=inf)minn++; if(res<=x)minn=1; updmn(p[i],minn); updmx(p[i],maxn); l=minn;r=maxn; } return l<=k&&k<=r; } int main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; vec.pb(mp(sum[i],i)); } sort(vec.begin(),vec.end()); for(int i=0;i<vec.size();i++)p[vec[i].second]=i+1; ll l=-inf,r=inf,ans; while(l<=r){ ll mid=(l+r)/2; if(check(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%lld\n",ans); return 0; } /* 3 2 -1 -2 3 */

「長樂集訓 2017 Day10」劃分序列 (二分 dp)