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;
    }
    
  • 相关阅读:
    C/C++多文件之间的变量定义
    PKU POJ 2186 Popular Cows 强连通分量
    重载函数
    ZOJ 2763 Prison Break
    201357 训练赛总结
    hdu 4467 Graph 构造
    201356 训练赛总结
    201353 NEERC 2012, Eastern subregional contest
    2013512 CF 183 总结
    一道动态规划
  • 原文地址:https://www.cnblogs.com/jz-597/p/14146648.html
Copyright © 2011-2022 走看看