「长乐集训 2017 Day10」划分序列 (二分 dp)
Posted 贱人方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「长乐集训 2017 Day10」划分序列 (二分 dp)相关的知识,希望对你有一定的参考价值。
「长乐集训 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 100n≤100
另有 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 10K≤10
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 ^ 41≤K≤n≤5×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)的主要内容,如果未能解决你的问题,请参考以下文章