zoukankan      html  css  js  c++  java
  • NOIP2020 T3移球游戏

    题目描述

    (n)个柱子,每个柱子上面(m)个大小相同、颜色不同的球,寻找一种移球方案使得每个柱子上面的球颜色相同。

    题解

    这题思维难度比较高,代码实现难度不大,考场打了一个假掉的做法,看了正解以后感觉非常之妙。

    做法挺自然的,首先考虑只有两种颜色的情况:

    • 考虑将所有黑色的球移动到白色的球上方。具体来说:先将要操作的柱子找出来,找到其里面有多少个黑球(设有(k)个),将随便另外一个柱子最上方的(k)个球移到空柱上,然后操作这个柱子,将黑球移到我们选的柱子上,白球移到空柱上,再将黑球和白球先后移会来,因为每时每刻空余位置数都是(m),所以是合法的。
    • 然后考虑将每种颜色的球移动到一个柱子上。可以考虑对于每一个要操作的柱子,找到另外一个要操作的柱子,分黑球数之和大于(m)和小于(m)来讨论,就可以容易实现。

    对于(n>2)的情况,可以考虑分治,将所有球染为黑白两色,同颜色的也染为同颜色,然后给这些球各自分配一半的柱子,然后继续递归下去就可以解决了。大概计算一下,总共的移球次数是在(800000)左右。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 60
    #define M 500
    using namespace std;
    int n,m,i,j,c[N][M],ans,ans1[1000000][3],num,id[M],cnt[N];
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (ch>'9'||ch<'0') ch=getchar();
    	while (ch>='0'&&ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x;
    }
    void move(int x,int y,int num){
    	int i;
    	for (i=1;i<=num;i++){
    		cnt[x]--;cnt[y]++;
    		c[y][cnt[y]]=c[x][cnt[x]+1];c[x][cnt[x]+1]=0;
    		ans++;
    		ans1[ans][1]=x;ans1[ans][2]=y;
    	}
    }
    void dfs(int l,int r){
    	int mid=(l+r)/2,i,j,sum,x,y,s1,s2;
    	if (l==r) return;
    	num=0;
    	for (i=1;i<=n;i++)
    		if (c[i][1]>=l&&c[i][2]<=r)
    			id[++num]=i;
    	for (i=1;i<=num;i++){
    		sum=0;
    		x=id[i];y=id[i%num+1];
    		for (j=1;j<=m;j++)
    			if (c[x][j]>=l&&c[x][j]<=mid) sum++;
    		if (!sum) continue;
    		move(y,n+1,sum);
    		s1=s2=0;
    		for (j=m;j>=1;j--){
    			if (s1>=sum) break;
    			if (c[x][j]>=l&&c[x][j]<=mid){
    				s1++;
    				move(x,y,1);
    			}
    			else{
    				s2++;
    				move(x,n+1,1);
    			}
    		}
    		move(n+1,x,s2);
    		move(y,x,s1);
    		move(n+1,y,s1);
    	}
    	for (i=1;i<=num-1;i++){
    		x=id[i];y=id[i%num+1];
    		s1=s2=0;
    		for (j=1;j<=m;j++){
    			if (c[x][j]>=l&&c[x][j]<=mid) s1++;
    			if (c[y][j]>=l&&c[y][j]<=mid) s2++;
    		}
    		if (s1==m||s1==0) continue;
    		if (s1+s2>m){
    			move(x,n+1,m);
    			move(y,x,s2);
    			move(n+1,y,m-s1);
    			move(n+1,x,m-s2);
    			move(n+1,y,cnt[n+1]);
    		}
    		else{
    			move(x,n+1,s1);
    			move(y,n+1,s2);
    			move(y,x,s1);
    			move(n+1,y,s1+s2);
    		}
    	}
    	dfs(l,mid);dfs(mid+1,r);
    }
    int main(){
    	freopen("ball.in","r",stdin);
    	freopen("ball.out","w",stdout);
    	n=read();m=read();
    	for (i=1;i<=n;i++){
    		cnt[i]=m;
    		for (j=1;j<=m;j++)
    			c[i][j]=read();
    	}
    	dfs(1,n);
    	printf("%d
    ",ans);
    	for (i=1;i<=ans;i++) printf("%d %d
    ",ans1[i][1],ans1[i][2]);
    	return 0;
    }
    
  • 相关阅读:
    go语言编程之旅笔记5
    go语言编程之旅笔记4
    go语言编程之旅笔记3
    go语言编程之旅笔记1~2
    minikube使用记录
    Azure Sql : Could not find stored procedure 'sp_addlinkedserver'.
    Jenkins SVN WebDeploy远程服务器
    sqlserver使用cte实现某列按字符分隔成多行
    openstack安装记录
    C语言中的bzero函数
  • 原文地址:https://www.cnblogs.com/Mohogany/p/14151843.html
Copyright © 2011-2022 走看看