1 条题解
-
0
注意力惊人的注意到答案 ,证明考虑在原序列上或在取反序列上找到前缀和序列的最大最小值,然后向前向后各跑一次即可。
考虑继续挖掘性质。 情况显然,不过 启示我们最后一次 操作一定可以是全局操作。
若 ,要么是因为可以通过取反转化成一个 的情况,要么是因为可以通过一次 操作转化为一个可以只做一次全局 操作的情况。若 ,就是可以通过一次取反转化为刚才所说的 的第二种情况。
难点在于 的第二种情况,考虑不妨设全局操作做 操作,对第一次操作类型进行分讨:
-
第一次操作类型为 。那么我们容易发现第一次操作前缀一定不劣,然后暴力找到第一个前缀和 的地方,尝试对这个区间进行一次操作,看看能否转化成一个可用一次全局 解决的情况。
-
第一次操作类型为 。设操作区间为 ,前缀和数组为 ,后缀和数组为 。考虑右移右端点,查找最优左端点,则有:
- 直接找出 满足 且 ,该性质就可以转化为 。
- 这个式子的来源是由于第一次操作后 内的每个数都会变成 ,则前缀和变为: 移项即可得到上述式子。 设 ,则上式可表示为: 显然不好处理,考虑按 划分,则有:$$f_l(r)-sum_r\le\min(\min\limits_{i=l}^{pos}f_i(r),\min\limits_{i=pos}^rf_i(r))$$显然左式取 时一定小于右侧前半部分,同时一定是对于右侧后半部分的最小解,所以只需 这个位置即可。
- $$(l-1)sum_r+S_l\le rsum_r+S_{r+1}+\min_{i=r+1}^n sum_i$$来源是 内部的数在 操作后前缀和变成: 移项即得上述式子。 发现左右独立,直接让左式最小即可,和 2 的要求等价。
所以,在经过深刻的分析后,我们得出结论:对于每个 ,最优的 。 是一个一次函数,李超线段树维护即可。时间复杂度 。
综上,我们在 的时间复杂度内解决了这个问题。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=2e5+5; int n,a[N],sum[N],ds[N],mns[N],fl,mx,mn,minn,flag,cnt[N]; struct line{ int k,b; inline int num(int x){return k*x+b;} };inline line lmin(line x,line y,int c){ return x.num(c)<y.num(c)?x:y; }struct Lichao{ line sg[N<<3]; inline void build(int x,int l,int r){ sg[x]={0,(int)1e18};if(l==r) return; int mid=(l+r)>>1;build(x<<1,l,mid); build(x<<1|1,mid+1,r); }inline void add(int x,int l,int r,line v){ int mid=(l+r)>>1; if(sg[x].num(mid)>v.num(mid)) swap(sg[x],v); if(sg[x].num(l)>v.num(l)) add(x<<1,l,mid,v); if(sg[x].num(r)>v.num(r)) add(x<<1|1,mid+1,r,v); }inline line num(int x,int l,int r,int k){ if(l==r) return sg[x]; int mid=(l+r)>>1;line re=sg[x]; if(k<=mid) return lmin(num(x<<1,l,mid,k),re,k); return lmin(num(x<<1|1,mid+1,r,k),re,k); } }tr1,tr2; inline int solve1(int x){ for(int i=1,sm=0;i<=n;i++){ sm+=(i<=x?sum[i]:a[i]); if(sm<0) return 0; }return x; }inline pair<int,int>solve2(int x){ tr1.build(1,-n,n); for(int l,r=1;r<x;r++){ tr1.add(1,-n,n,{r,ds[r]}); if(sum[r]>=0){ l=tr1.num(1,-n,n,sum[r]).k; if((l-1)*sum[r]+ds[l]<=r*sum[r]+ds[r+1]+mns[r+1]) return {l,r}; } }tr2.build(1,-n,n),tr1.add(1,-n,n,{1,ds[1]}); for(int l,mid,r=x;r<=n;r++){ tr2.add(1,-n,n,{r,ds[r]}); if(sum[r]>=0){ l=tr1.num(1,-n,n,sum[r]).k,mid=tr2.num(1,-n,n,sum[r]).k; if((l-1)*sum[r]+ds[l]<=r*sum[r]+ds[r+1]+mns[r+1]) if((l-1)*sum[r]+ds[l]<=mid*sum[r]+ds[mid]) return {l,r}; } }return {0,0}; }inline void solve(int id){ for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];mns[n+1]=1e18; for(int i=n;i;i--) ds[i]=ds[i+1]+sum[i],mns[i]=min(mns[i+1],sum[i]); fl=0;while(sum[fl]>=0) fl++;fl=solve1(fl); if(fl) cout<<id<<(id%2?"\n1\n":"\n")<<"2 1 "<<fl<<"\n2 1 "<<n,exit(0); fl=0;while(sum[fl]>=0) fl++;pair<int,int>pr=solve2(fl); if(pr.first){ cout<<id<<(id%2?"\n1\n":"\n")<<"3 "<<pr.first<<" "; cout<<pr.second<<"\n2 1 "<<n,exit(0); }for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];mns[n+1]=1e18; for(int i=n;i;i--) ds[i]=ds[i+1]+sum[i],mns[i]=min(mns[i+1],sum[i]); fl=0;while(sum[fl]>=0) fl++;fl=solve1(fl); if(fl) cout<<id<<(id%2?"\n1\n":"\n")<<"3 "<<n-fl+1<<" "<<n<<"\n3 1 "<<n,exit(0); fl=0;while(sum[fl]>=0) fl++;pr=solve2(fl); if(pr.first){ cout<<id<<(id%2?"\n1\n":"\n")<<"2 "<<n-pr.second+1<<" "; cout<<n-pr.first+1<<"\n3 1 "<<n,exit(0); }for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]); }signed main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n>>fl,fl=flag=1; for(int i=1;i<=n;i++){ cin>>a[i],fl&=(a[i]<=0),flag&=(a[i]>=0); if(a[i]<0) mx=i,mn=(mn?mn:i); }if(flag) cout<<0,exit(0); if(fl) cout<<"1\n1",exit(0); for(int i=mn,sm=0;i<=mx;i++) sm+=a[i],minn=min(minn,sm); for(int i=mn-1;i;i--){ minn+=a[i];if(minn>=0) cout<<"1\n2 1 "<<n,exit(0); }minn=0; for(int i=mx,sm=0;i>=mn;i--) sm+=a[i],minn=min(minn,sm); for(int i=mx+1;i<=n;i++){ minn+=a[i];if(minn>=0) cout<<"1\n3 1 "<<n,exit(0); }solve(2),minn=mx=mn=0; for(int i=1;i<=n;a[i]=-a[i],i++) if(a[i]>0) mx=i,mn=(mn?mn:i); for(int i=mn,sm=0;i<=mx;i++) sm+=a[i],minn=min(minn,sm); for(int i=mn-1;i;i--){ minn+=a[i];if(minn>=0) cout<<"2\n1\n2 1 "<<n,exit(0); }minn=0; for(int i=mx,sm=0;i>=mn;i--) sm+=a[i],minn=min(minn,sm); for(int i=mx+1;i<=n;i++){ minn+=a[i];if(minn>=0) cout<<"2\n1\n3 1 "<<n,exit(0); }return solve(3),0; } -
- 1
信息
- ID
- 10967
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者