NC218445 九峰与分割序列(线段树+dp)
套路题,首先发现dp可做
但是直接枚举复杂度太高,并且发现我们求的都是区间最值,因此考虑线段树优化
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e5+10; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; int n,k; int a[N]; ll sum[N]; ll f[N][2]; struct seg{ int l,r; ll mx; }; struct node{ seg tr[N<<2]; void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,-inf}; } else{ tr[u]={l,r,-inf}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void pushup(int u){ tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx); } void modify(int u,int l,ll x){ if(tr[u].l==tr[u].r){ tr[u].mx=x; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,x); else{ modify(u<<1|1,l,x); } pushup(u); } ll query(int u,int l,int r){ if(l>r) return 0; if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].mx; } int mid=tr[u].l+tr[u].r>>1; ll ans=-inf; if(l<=mid) ans=max(ans,query(u<<1,l,r)); if(r>mid) ans=max(ans,query(u<<1|1,l,r)); return ans; } }T[5]; int main(){ ios::sync_with_stdio(false); cin>>n>>k; int i; for(i=1;i<=3;i++) T[i].build(1,0,n); for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<=n;i++){ sum[i]=sum[i-1]+a[i]; } for(i=1;i<=n;i++){ f[i][0]=f[i][1]=-inf; if(i<=k) f[i][1]=sum[i]; else{ f[i][0]=max(T[1].query(1,1,i-k-1),T[2].query(1,1,i-k-1))+sum[i]; f[i][1]=T[3].query(1,i-k,i)+sum[i]*2; f[i][1]=max(f[i][1],T[2].query(1,i-k,i)+sum[i]); } T[1].modify(1,i,f[i][0]-sum[i]); T[2].modify(1,i,f[i][1]-sum[i]); T[3].modify(1,i,f[i][0]-sum[i]*2); } cout<<max(f[n][0],f[n][1])<<endl; return 0; }
没有人不辛苦,只有人不喊疼