NOIP2020 T3移球游戏

(n+1)个栈,一开始前(n)个栈中每个栈各有(m)个数。每种数的出现次数为(n)

每次将一个栈的栈顶取出丢到另一个栈的栈顶。要求操作之后栈大小不超过(m)

要求每个栈中元素相同。

(nle 50,mle 400)

操作次数限制(820000)


构造白痴表示连40分都不会。

讲正解:

考虑(n=2)的情况,分两步:将每个栈调整为上面白下面黑,然后再随便搞搞。

设栈(A)黑色有(x)个。如此操作:

  1. (B)(x)个数丢入(C)中。
  2. (A)中的所有数,如果是黑色丢入(B)中,否则丢入(C)中。
  3. (B)(x)个数(黑色)丢入(A)中,(C)(m-x)个数丢入(A)中。

可以发现,这样之后(A)被成功调整,而其它的没有变化。

考虑(n>2)。可以分治做,黑白染色后做上述操作。

搞完之后需要把栈变成全黑或全白。可以这样搞:随便取出两个栈,记(x,y)分别为它们的黑色出现次数。如果(x+yge m),将(A)(B)上的白色都丢入(C)中,把(B)中的黑色丢入(A)中,再将白色放回来;如果(x+y<m),把(A)全部丢入(C)中,把(B)的白色丢入(A)中,把(C)中的黑色丢到(B)中,剩下的白色丢到(A,B)中。

发现复杂度是(O(nmlg n))的,可以过。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cassert>
#define N 55
#define M 405
int n,m;
int a[N][M],c[N];
pair<int,int> o[1000000];
int oc;
void opt(int x,int y){
	o[++oc]={x,y};	
	assert(c[y]<m);
	assert(c[x]>0);
	a[y][++c[y]]=a[x][c[x]--];
}
int cnt(int i,int mid){
	assert(c[i]==m);
	int s=0;
	for (int j=1;j<=m;++j)
		s+=(a[i][j]<=mid);
	return s;
}
void divide(vector<int> p,int l,int r){
	if (p.size()==1)
		return;
	int mid=l+r>>1;
	for (int ii=0;ii<p.size();++ii){
		int i=p[ii],t=(i==1?n:1),x=cnt(i,mid);
		for (int j=1;j<=x;++j)
			opt(t,n+1);
		for (int j=m;j>=1;--j)
			if (a[i][j]<=mid)
				opt(i,t);
			else
				opt(i,n+1);
		for (int j=1;j<=x;++j)
			opt(t,i);
		for (int j=1;j<=m-x;++j)
			opt(n+1,i);
		for (int j=1;j<=x;++j)
			opt(n+1,t);
	}
	vector<int> lp,rp;
	lp.clear(),rp.clear();
	for (int ii=0;ii<p.size();++ii){
		int i=p[ii],x=cnt(i,mid);
		if (x==m)
			lp.push_back(i);
		else if (x==0)
			rp.push_back(i);
		else{
			int t=p[ii+1],y=cnt(t,mid);
			if (x+y>=m){
				for (int j=1;j<=m-x;++j)
					opt(i,n+1);
				for (int j=1;j<=m-y;++j)
					opt(t,n+1);
				for (int j=1;j<=m-x;++j)
					opt(t,i);
				for (int j=1;j<=m-y+m-x;++j)
					opt(n+1,t);
				lp.push_back(i);
			}
			else{
				for (int j=1;j<=m;++j)
					opt(i,n+1);
				for (int j=1;j<=m-y;++j)
					opt(t,i);
				for (int j=1;j<=x;++j)
					opt(n+1,t);
				for (int j=1;j<=y;++j)
					opt(n+1,i);
				for (int j=1;j<=m-x-y;++j)
					opt(n+1,t);
				rp.push_back(i);
			}
		}
	}
//	for (int i=0;i<lp.size();++i)
//		for (int j=1;j<=m;++j)
//			assert(a[lp[i]][j]<=mid);
	divide(lp,l,mid);
	divide(rp,mid+1,r);
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i){
		for (int j=1;j<=m;++j)
			scanf("%d",&a[i][j]);
		c[i]=m;
	}
	vector<int> p;
	p.clear();
	for (int i=1;i<=n;++i)
		p.push_back(i);
	divide(p,1,n);
	printf("%d
",oc);
	for (int i=1;i<=oc;++i)
		printf("%d %d
",o[i].first,o[i].second);
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14146648.html