[BJOI2017]Round 1

太空飞船

Description
环上有 N 个整数 \(l_i\)。要把环划分成 K 段,使得每段之和的方差最小。

HINT
三个部分:

  1. \(K=2,N\leq10^5\).
  2. \(K=3,N\leq3\times10^5\).
  3. \(K\leq20,N\leq400\).

Solution
第一部分直接枚举一个断点,另一个断点三分即可.

第二部分将环复制两遍,直接枚举一个断点,另外两个断点肯定是在总和的三分点附近.

第三部分比较麻烦.

把方差的式子展开发现,其实只需最小化每段之和的平方的和.

\(f[i][j]\) 表示前 \(j\) 个数分成 \(i\) 段的最小值.

\(f[i][j]=min\{f[i-1][k]+(s[j]-s[k])^2\}\).

撇开 \(i\) 那一维考虑一下斜率优化.

如果 \(k1>k2\)\(f[j]_{k_1}<f[j]_{k_2}\) 的情况:

\(f[k_1]+(s[j]-s[k_1])^2<f[k_2]+(s[j]-s[k_2])^2\)

\(f[k_1]+s[j]^2-2\times s[j]\times s[k_1]+s[k_1]^2<f[k_2]+s[j]^2-2\times s[j]\times s[k_2]+s[k_2]^2\)

\(f[k_1]+s[k_1]^2-f[k_2]-s[k_2]^2<2\times s[j]\times(s[k_1]-s[k_2])\)

\(\frac{f[k_1]+s[k_1]^2-f[k_2]-s[k_2]^2}{s[k_1]-s[k_2]}<2\times s[j]\)

考虑队列中的情况:

如果当前比其优的,后面也一定比其优;如果当前比其劣的,后面有可能比其优.

\(\frac{f[k_1]+s[k_1]^2-f[k_2]-s[k_2]^2}{s[k_1]-s[k_2]}\) 维护上升序列,每次操作前弹出劣的队头,取队头为 \(k\).

#define K 21
#define M 401
#define N 600001
using namespace std;
ll f[K][M],ans,inf; 
int l[N],s[N],q[N],n,k,h,t;
inline ll sqr(int x){
	return 1ll*x*x;
}
inline ll g(int x){
	return k*sqr(x)-2ll*s[n]*x;
}
inline ll G(int x,int i){
	return f[i-1][x]+sqr(s[x]);
}
inline void Aireen(){
	n=read();k=read();
	for(int i=1;i<=n;++i) s[i]=l[i]=read();
	for(int i=1;i<=n;++i) s[i]+=s[i-1];
	if(k==2){
		for(int i=1;i<k;++i) inf+=g(l[i]);
		inf+=g(s[n]-s[k-1]);ans=inf;
		for(int i=1;i<=n;++i) s[i+n]=l[i+n]=l[i];
		for(int i=1;i<=n;++i) s[i+n]+=s[i+n-1];
		int lef,rig,m1,m2;
		for(int i=0;i<n;++i){
			lef=i+1;rig=i+n-1;
			while(lef<rig){
				m2=(rig-lef+1)/3;m1=lef+m2;m2+=m1;
				if(g(s[m1]-s[i])+g(s[i+n]-s[m1])<=g(s[m2]-s[i])+g(s[i+n]-s[m2])) rig=m2-1;
				else lef=m1+1;
			}
			ans=min(g(s[lef]-s[i])+g(s[i+n]-s[lef]),ans);
		}
		printf("%lld\n",1ll*k*(ans+sqr(s[n])));
		return;
	}
	if(n<=M){
		for(int i=1;i<k;++i) inf+=sqr(l[i]);
		inf+=sqr(s[n]-s[k-1]);ans=inf;
		for(int x=1;x<=n;++x){
			for(int i=1;i<=n;++i) f[1][i]=sqr(s[i]);
			for(int i=2;i<=k;++i){
				h=1;t=0;q[++t]=i-1;
				for(int j=i;j<=n;++j){
					f[i][j]=inf;
					while(h<t&&(G(q[h+1],i)-G(q[h],i))<2ll*s[j]*(s[q[h+1]]-s[q[h]])) ++h;
					f[i][j]=min(f[i][j],f[i-1][q[h]]+sqr(s[j]-s[q[h]]));
					while(h<t&&(G(j,i)-G(q[t],i))*(s[q[t]]-s[q[t-1]])<(G(q[t],i)-G(q[t-1],i))*(s[j]-s[q[t]])) --t;
					q[++t]=j;
				}
			}
			ans=min(ans,f[k][n]);
			for(int i=1;i<=n;++i)
				l[i-1]=l[i];
			l[n]=l[0]; 
			for(int i=1;i<=n;++i)
				s[i]=s[i-1]+l[i];
		}
		printf("%lld\n",ans*sqr(k)-1ll*k*sqr(s[n]));
		return;
	}
	if(k==3){
		for(int i=1;i<k;++i) inf+=sqr(l[i]);
		inf+=sqr(s[n]-s[k-1]);ans=inf;
		for(int i=1;i<=n;++i) s[i+n]=l[i+n]=l[i];
		for(int i=1;i<=n;++i) s[i+n]+=s[i+n-1];
		for(int i=0,j=1,y=1,x=s[n]/3,z,r;i<n;++i){
			r=i+n;//(i,r]
			while(j+2<r&&s[j]-s[i]<=x) ++j;
			z=s[r]-s[j]>>1;
			if(y<j) y=j;
			while(y+1<r&&s[y]-s[j]<=z) ++y;
			while(y-2>i&&s[y-1]-s[j]>=z) --y;
			ans=min(ans,sqr(s[j]-s[i])+sqr(s[y]-s[j])+sqr(s[r]-s[y]));
			if(y-1>i)ans=min(ans,sqr(s[j]-s[i])+sqr(s[y-1]-s[j])+sqr(s[r]-s[y-1]));
			if(y+1<r) ans=min(ans,sqr(s[j]-s[i])+sqr(s[y+1]-s[j])+sqr(s[r]-s[y+1]));
			if(j+1<r){
				ans=min(ans,sqr(s[j+1]-s[i])+sqr(s[y]-s[j+1])+sqr(s[r]-s[y]));
				if(y-1>i)ans=min(ans,sqr(s[j+1]-s[i])+sqr(s[y-1]-s[j+1])+sqr(s[r]-s[y-1]));
				if(y<r) ans=min(ans,sqr(s[j+1]-s[i])+sqr(s[y+1]-s[j+1])+sqr(s[r]-s[y+1]));
			}
			if(j-1>i){
				ans=min(ans,sqr(s[j-1]-s[i])+sqr(s[y]-s[j-1])+sqr(s[r]-s[y]));
				if(y-1>i)ans=min(ans,sqr(s[j-1]-s[i])+sqr(s[y-1]-s[j-1])+sqr(s[r]-s[y-1]));
				if(y+1<r) ans=min(ans,sqr(s[j-1]-s[i])+sqr(s[y+1]-s[j-1])+sqr(s[r]-s[y+1]));
			}
		}
		printf("%lld\n",ans*sqr(k)-1ll*k*sqr(s[n]));
		return;
	}
}

神秘物质

Description
给定一个有 N 个原子的序列 \(e_i\)
维护以下 4 种操作,共有 M 个操作:

  1. merge x e 当前第 x 个原子和第 x+1 个原子合并,得到能量为 e 的新原子;
  2. insert x e 在当前第 x 个原子和第 x+1 个原子之间插入一个能量为 e 的新原子;
  3. max x y 询问当前第 x 到第 y 个原子之间的任意子区间中区间极差的最大值;
  4. min x y 询问当前第 x 到第 y 个原子之间的任意子区间中区间极差的最小值。
    其中,子区间指的是长度至少是 2 的子区间。

HINT
\(N,M\leq10^5\).

Solution
可以发现,第3种操作等价于求区间最大值-区间最小值;第3种操作等价于求区间相邻两数之差的最小值.
splay维护下标直接上.

#define N 200005
#define INF 1000000001
struct Splay{
	int c[2],f,mx,mi,di,li,ri,siz,val;
}tr[N];
int e[N],n,m,rt,cnt;
inline void recnt(int u){
	int lef=tr[u].c[0],rig=tr[u].c[1];
	tr[u].siz=tr[lef].siz+tr[rig].siz+1;
	tr[u].mx=tr[u].mi=tr[u].val;tr[u].di=INF;
	if(!lef) tr[u].li=tr[u].val; 
	else{
		tr[u].mx=max(tr[lef].mx,tr[u].mx);
		tr[u].mi=min(tr[lef].mi,tr[u].mi);
		tr[u].li=tr[lef].li;
		tr[u].di=min(tr[lef].di,tr[u].di);
		tr[u].di=min(tr[u].di,abs(tr[lef].ri-tr[u].val));
	}
	if(!rig) tr[u].ri=tr[u].val; 
	else{
		tr[u].mx=max(tr[u].mx,tr[rig].mx);
		tr[u].mi=min(tr[u].mi,tr[rig].mi);
		tr[u].ri=tr[rig].ri;
		tr[u].di=min(tr[u].di,tr[rig].di);
		tr[u].di=min(tr[u].di,abs(tr[u].val-tr[rig].li));
	}
}
inline void build(int l,int r,int f){
	int mid=(l+r)>>1;
	if(l<r){
		if(l<mid) build(l,mid-1,mid);
		if(mid<r) build(mid+1,r,mid);
	}
	else if(l==r){
		tr[mid].di=INF;tr[mid].siz=1;
		tr[mid].li=tr[mid].ri=tr[mid].mx=tr[mid].mi=e[mid];
	}
	tr[mid].val=e[mid];tr[mid].f=f;recnt(mid);
	tr[f].c[mid<f?0:1]=mid;
}
inline int kth(int k){
	int u=rt;
	while(tr[u].siz-tr[tr[u].c[1]].siz!=k){
		if(k<=tr[tr[u].c[0]].siz) u=tr[u].c[0];
		else k-=tr[u].siz-tr[tr[u].c[1]].siz,u=tr[u].c[1];
	}
	return u;
}
inline bool son(int u){
	return tr[tr[u].f].c[1]==u;
}
inline void ins_p(int f,int u,bool c){
	tr[f].c[c]=u;tr[u].f=f;
}
inline void rotate(int u){
	int f=tr[u].f;bool c=son(u);
	if(!tr[f].f){
		rt=u;tr[u].f=0;
	}
	else ins_p(tr[f].f,u,son(f));
	ins_p(f,tr[u].c[c^1],c);
	ins_p(u,f,c^1);
	recnt(f);recnt(u); 
}
inline void splay(int u,int f){
	while(tr[u].f!=f){
		if(tr[tr[u].f].f==f) rotate(u);
		else if(son(u)==son(tr[u].f)){
			rotate(tr[u].f);rotate(u); 
		}
		else{
			rotate(u);rotate(u); 
		}
	}
}
inline int near(int u,bool c){
	if(tr[u].c[c]){
		u=tr[u].c[c];c^=1;
		while(tr[u].c[c])
			u=tr[u].c[c];
		return u;
	}
	while(u&&son(u)==c) u=tr[u].f;
	return tr[u].f;
}
inline int select(int u,int v){
	u=kth(u);v=kth(v);
	u=near(u,0);v=near(v,1);
	splay(u,0);splay(v,rt);
	return tr[v].c[0];
}
inline void mx(int l,int r){
	int u=select(l,r);
	printf("%d\n",tr[u].mx-tr[u].mi);
}
inline void mi(int l,int r){
	int u=select(l,r);
	printf("%d\n",tr[u].di);
}
inline void clear(int u){
	tr[tr[u].f].c[son(u)]=0;
	tr[u].c[0]=tr[u].c[1]=tr[u].f=tr[u].mx=tr[u].mi=tr[u].di=tr[u].li=tr[u].ri=tr[u].siz=tr[u].val=0;
}
inline void del(int u,int v){
	u=select(u,v);
	int f=tr[u].f;clear(u);u=f;
	while(u){
		recnt(u);u=tr[u].f;
	}
}
inline void ins(int u,int k){
	e[++cnt]=k;build(cnt,cnt,0);
	int x=kth(u),y=kth(u+1);
	splay(x,0);splay(y,rt);
	ins_p(cnt,y,1);ins_p(x,cnt,1);
	recnt(cnt);recnt(x);
}
inline void merge(int u,int k){
	del(u,u+1);ins(u-1,k);
}
inline void insert(int u,int k){
	ins(u,k);
}
inline void Aireen(){
	n=read();m=read();
	cnt=n+2;e[1]=e[cnt]=INF;
	for(int i=1;i<=n;++i) e[i+1]=read();
	rt=(1+cnt)>>1;build(1,cnt,0);
	char c[10];int x,y;
	while(m--){
		scanf("%s",&c);x=read();y=read();
		if(c[1]=='a')/*max*/mx(x+1,y+1);
		else if(c[1]=='i')/*min*/mi(x+1,y+1);
		else if(c[1]=='e')/*merge*/merge(x+1,y);
		else/*insert*/insert(x+1,y); 
	}
}

2017-04-21 15:28:26

posted @ 2021-11-25 15:52  Aireen_Ye  阅读(35)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.