bzoj4367 [IOI2014]holiday假期
题解:
很明显总体路径可以是一直向左/向右,或者先向一个方向跑几步,然后反向跑。
所以我们可以得到四种基本运动方式:
LGL:一直向左;
RGR:一直向右;
LGR:先向左,然后向右回到原点;
RGL:先向右,然后向左回到原点。
然后决策单调,分治求解上面四个东西,最后合并出结果。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 #define ll long long inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,st,d,a[N]; ll to[N]; struct Pair { int x,id; }p0[N]; bool cmp(Pair a,Pair b) { return a.x<b.x; } struct ptree { int rt[N],tot,siz[N*20],ch[N*20][2]; ll vl[N*20]; void insert(int l,int r,int &u,int br,int qx,ll d) { u=++tot; ch[u][0]=ch[br][0],ch[u][1]=ch[br][1],siz[u]=siz[br]+1,vl[u]=vl[br]+d; if(l==r)return ; int mid = (l+r)>>1; if(qx<=mid)insert(l,mid,ch[u][0],ch[br][0],qx,d); else insert(mid+1,r,ch[u][1],ch[br][1],qx,d); } void build() { for(int i=1;i<=n;i++) insert(1,n,rt[i],rt[i-1],a[i],to[a[i]]); } ll query(int l,int r,int ul,int ur,int k) { if(siz[ur]-siz[ul]<=k)return vl[ur]-vl[ul]; if(l==r)return vl[ur]/siz[ur]*k; int mid = (l+r)>>1; if(siz[ch[ur][1]]-siz[ch[ul][1]]>=k)return query(mid+1,r,ch[ul][1],ch[ur][1],k); else return vl[ch[ur][1]]-vl[ch[ul][1]]+query(l,mid,ch[ul][0],ch[ur][0],k-(siz[ch[ur][1]]-siz[ch[ul][1]])); } ll ask(int ul,int ur,int k) { if(k<=0)return 0; return query(1,n,rt[ul],rt[ur],k); } }tr; ll lgl[N<<2],rgr[N<<2],lgr[N<<2],rgl[N<<2]; void LGL(int l1,int r1,int l2,int r2) { int mid = (l1+r1)>>1; int pos=l2;ll now = 0; for(int i=l2;i<=r2;i++) { ll tmp = tr.ask(i-1,st-1,mid-st+i); if(tmp>=now) { now=tmp; pos=i; } } lgl[mid] = now; if(l1<mid)LGL(l1,mid-1,pos,r2); if(r1>mid)LGL(mid+1,r1,l2,pos); } void RGR(int l1,int r1,int l2,int r2) { int mid = (l1+r1)>>1; int pos=l2;ll now = 0; for(int i=l2;i<=r2;i++) { ll tmp = tr.ask(st,i,mid-i+st); if(tmp>=now) { now=tmp; pos=i; } } rgr[mid] = now; if(l1<mid)RGR(l1,mid-1,l2,pos); if(r1>mid)RGR(mid+1,r1,pos,r2); } void LGR(int l1,int r1,int l2,int r2) { int mid = (l1+r1)>>1; int pos=l2;ll now = 0; for(int i=l2;i<=r2;i++) { ll tmp = tr.ask(i-1,st-1,mid-2*st+2*i); if(tmp>=now) { now=tmp; pos=i; } } lgr[mid] = now; if(l1<mid)LGR(l1,mid-1,pos,r2); if(r1>mid)LGR(mid+1,r1,l2,pos); } void RGL(int l1,int r1,int l2,int r2) { int mid = (l1+r1)>>1; int pos=l2;ll now = 0; for(int i=l2;i<=r2;i++) { ll tmp = tr.ask(st,i,mid-2*i+2*st); if(tmp>=now) { now=tmp; pos=i; } } rgl[mid] = now; if(l1<mid)RGL(l1,mid-1,l2,pos); if(r1>mid)RGL(mid+1,r1,pos,r2); } int main() { // freopen("4.in","r",stdin); n=rd(),st=rd()+1,d=rd(); for(int i=1;i<=n;i++)p0[i].x=rd(),p0[i].id=i; sort(p0+1,p0+1+n,cmp); for(int las=-1,k=0,i=1;i<=n;i++) { if(las!=p0[i].x) { las=p0[i].x; to[++k]=las; } a[p0[i].id]=k; } tr.build(); LGL(1,d,1,st); LGR(1,d,1,st); RGL(1,d,st,n);RGR(1,d,st,n); ll ans = 0; for(int i=0;i<=d;i++) ans=max(ans,max(lgl[i]+rgl[d-i],rgr[i]+lgr[d-i])); for(int i=0;i<d;i++) ans=max(ans,max(lgl[i]+rgl[d-i-1],rgr[i]+lgr[d-i-1])+to[a[st]]); printf("%lld\n",ans); return 0; }