zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    CF991D Bishwock
    CF1010D Mars rover
    NOIP 2011 计算系数
    SDOI 2008 仪仗队
    浅谈欧拉函数
    CF1249F Maximum Weight Subset
    NOIP 2011 铺地毯
    CF707D Persistent Bookcase
    C++ STL bitset 容器详解
    CF798D Mike and distribution
  • 原文地址:https://www.cnblogs.com/jz-597/p/14146648.html
Copyright © 2011-2022 走看看