2021.7.21 义乌模拟赛 T4 D
这种选\(k\)条的东西一般就是wqs二分。
这道题目显然有凸性,然后就可以二分斜率了。
但是这个输出方案很难搞,按照wqs二分分的方案只有90分因为有斜率相同。
我们考虑对每个点维护两个值\(L\)和\(R\)表示最小和最大能选的段数。
这个东西dp的时候稍微处理一下就好了。
然后我们对于每一个点\(i\),如果\(i\)为右端点,那么要满足\(L_i\leq k\leq R_i\),且左端点\(j\)满足\(L_j\leq k-1\leq R_{j}\)
然后就可做了。时间复杂度\(O(nlogn)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db long double
#define N 100000
#define M 20000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,x,y,z,now,g[N+5];ll Sum[N+5],dp[N+5],l,r,mid,A[N+5];
I int check(ll mid){
re int i,j;now=0;for(i=1;i<=n;i++){
dp[i]=dp[i-1];g[i]=g[i-1];(dp[now]-Sum[now+1]<dp[i-1]-Sum[i]||(dp[now]-Sum[now+1]==dp[i-1]-Sum[i]&&g[i-1]>g[now]))&&(now=i-1);
if(dp[now]+Sum[i]-Sum[now+1]+mid>dp[i]||(dp[now]+Sum[i]-Sum[now+1]+mid==dp[i]&&g[now]+1>g[i]))dp[i]=dp[now]+Sum[i]-Sum[now+1]+mid,g[i]=g[now]+1;
}return g[n]>=k;
}
struct Solve2{
int las,L[N+5],R[N+5],op,Ansl[N+5],Ansr[N+5],now1,now2,cnt;
I void calc(int mid){
re int i;for(i=1;i<=n;i++){
dp[i]=dp[i-1];L[i]=L[i-1];R[i]=R[i-1];
(dp[now1]-Sum[now1+1]<dp[i-1]-Sum[i]||(dp[now1]-Sum[now1+1]==dp[i-1]-Sum[i]&&L[i-1]<L[now1]))&&(now1=i-1);
(dp[now2]-Sum[now2+1]<dp[i-1]-Sum[i]||(dp[now2]-Sum[now2+1]==dp[i-1]-Sum[i]&&R[i-1]>R[now2]))&&(now2=i-1);
(dp[now1]+Sum[i]-Sum[now1+1]+mid>dp[i]||(dp[now1]+Sum[i]-Sum[now1+1]+mid==dp[i]&&L[now1]+1<L[i]))&&(L[i]=L[now1]+1);
(dp[now2]+Sum[i]-Sum[now2+1]+mid>dp[i]||(dp[now2]+Sum[i]-Sum[now2+1]+mid==dp[i]&&R[now2]+1>R[i]))&&(R[i]=R[now2]+1);
dp[i]=max(dp[now1]+Sum[i]-Sum[now1+1]+mid,dp[i]);
}
for(i=n;i;i--){
if(!op){
if(L[i]<=k&&R[i]>=k&&((dp[i]==dp[Ansl[cnt]-1]||!cnt)&&(dp[i]^dp[i-1]||L[i-1]>k||R[i-1]<k)))Ansr[++cnt]=i,op=1;
}if(op){
if(L[i-1]<=k-1&&R[i-1]>=k-1&&(dp[i-1]+Sum[Ansr[cnt]]-Sum[i]+mid==dp[Ansr[cnt]])) Ansl[cnt]=i,op=0,k--;
}
}for(i=1;i<=cnt;i++) printf("%d %d\n",Ansl[i],Ansr[i]);
}
}S;
int main(){
freopen("d.in","r",stdin);freopen("d.out","w",stdout);
re int i;scanf("%d%d",&n,&k);for(i=2;i<=n;i++) scanf("%lld",&A[i]),Sum[i]=Sum[i-1]+A[i];
l=-1e10+7;r=1e10+7;while(l+1<r) mid=l+r>>1,(check(mid)?r:l)=mid;check(r);printf("%lld\n",dp[n]-r*k);S.calc(r);
}