P7115-[NOIP2020]移球游戏【构造】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P7115


1|1题目大意

n+1个柱子,前面n个上面各有m个球,球有n种颜色,每种m个。

你每次可以把一个柱子最上面的球放到另一个上面,要求在820000次内使得同种颜色的球都在同一个柱子上。

输出方案

2n50,2m400


1|2解题思路

这题好难啊,用的是洛谷题解上的做法。

首先我们枚举一种颜色x,将这种颜色标记为1其他都为0

然后开始的状态是这样的
在这里插入图片描述
然后考虑先构造一个全部都是0的竖列

我们先记录第一柱的1的个数tmp,然后把第n1柱子的tmp个丢进第n+1柱,然后把第一柱分离到后面两个柱子(1的放到n0的放到n+1
在这里插入图片描述
然后把原来的0放到第一柱,然后分离第二柱,如果是0放到第一柱否则放到第n+1柱(如果第一柱已经满了就放进n+1柱)

在这里插入图片描述
然后交换一下柱子序号(用个数组存一下就好了)就变成了
在这里插入图片描述
然后再考虑构造全1

我们把同理把第1柱分裂到第n和第n+1柱就变成了
在这里插入图片描述
此时第n+1柱子上面全部是1而第n柱上面都是0,然后此时我们再把剩下n个柱子依次分离就能把所有的1提到最上面,然后把所有的1集合就好了。

最后弄出n1个全0柱和一个全1柱我们就可以把全一柱去掉然后缩小n的值。

一直重复到n=2时我们发现我们的方法不再适用,需要特别处理。

我们按照前面的方法把第一柱分离到23
在这里插入图片描述
然后把01丢到第一个柱子,然后再把1丢进第3个柱子
在这里插入图片描述
然后分离第二个柱子就好了

然后这样就能过了


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=410; int n,m,a[N][N],cnt[N],p[N]; vector<int> aL,aR; void mov(int x,int y){ aL.push_back(x); aR.push_back(y); a[y][++cnt[y]]=a[x][cnt[x]--]; return; } int count(int x,int y){ int ans=0; for(int i=1;i<=m;i++) ans+=(a[x][i]==y); return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); cnt[i]=m;p[i]=i; } p[n+1]=n+1; for(int k=n;k>=3;k--){ int tmp=count(p[1],k); for(int i=1;i<=tmp;i++)mov(p[k],p[k+1]); for(int i=1;i<=m;i++) if(a[p[1]][cnt[p[1]]]==k)mov(p[1],p[k]); else mov(p[1],p[k+1]); for(int i=1;i<=m-tmp;i++)mov(p[k+1],p[1]); for(int i=1;i<=m;i++) if(a[p[2]][cnt[p[2]]]==k)mov(p[2],p[k+1]); else if(cnt[p[1]]<m)mov(p[2],p[1]); else mov(p[2],p[k+1]); swap(p[1],p[k]);swap(p[2],p[k+1]); for(int i=1;i<k;i++){ int tmp=count(p[i],k); for(int j=1;j<=tmp;j++)mov(p[k],p[k+1]); for(int j=1;j<=m;j++) if(a[p[i]][cnt[p[i]]]==k)mov(p[i],p[k]); else mov(p[i],p[k+1]); swap(p[i],p[k+1]);swap(p[k],p[i]); } for(int i=1;i<k;i++){ while(a[p[i]][cnt[p[i]]]==k)mov(p[i],p[k+1]); while(cnt[p[i]]<m)mov(p[k],p[i]); } } int tmp=count(p[1],1); for(int i=1;i<=tmp;i++)mov(p[2],p[3]); for(int i=1;i<=m;i++) if(a[1][cnt[p[1]]]==1)mov(p[1],p[2]); else mov(p[1],p[3]); for(int i=1;i<=m-tmp;i++)mov(p[3],p[1]); for(int i=1;i<=tmp;i++)mov(p[2],p[1]); while(cnt[p[3]])mov(p[3],p[2]); for(int i=1;i<=tmp;i++)mov(p[1],p[3]); for(int i=1;i<=m;i++) if(a[2][cnt[p[2]]]==1)mov(p[2],p[3]); else mov(p[2],p[1]); printf("%d\n",aL.size()); for(int i=0;i<aL.size();i++) printf("%d %d\n",aL[i],aR[i]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14894765.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(85)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示