P7115-[NOIP2020]移球遊戲【構造】
阿新 • • 發佈:2021-06-17
正題
題目連結:https://www.luogu.com.cn/problem/P7115
題目大意
\(n+1\)個柱子,前面\(n\)個上面各有\(m\)個球,球有\(n\)種顏色,每種\(m\)個。
你每次可以把一個柱子最上面的球放到另一個上面,要求在\(820000\)次內使得同種顏色的球都在同一個柱子上。
輸出方案
\(2\leq n\leq 50,2\leq m\leq 400\)
解題思路
這題好難啊,用的是洛谷題解上的做法。
首先我們列舉一種顏色\(x\),將這種顏色標記為\(1\)其他都為\(0\)。
然後開始的狀態是這樣的
然後考慮先構造一個全部都是\(0\)的豎列
我們先記錄第一柱的\(1\)
然後把原來的\(0\)放到第一柱,然後分離第二柱,如果是\(0\)放到第一柱否則放到第\(n+1\)柱(如果第一柱已經滿了就放進\(n+1\)柱)
然後交換一下柱子序號(用個數組存一下就好了)就變成了
然後再考慮構造全\(1\)柱
我們把同理把第\(1\)柱分裂到第\(n\)和第\(n+1\)柱就變成了
此時第\(n+1\)柱子上面全部是\(1\)而第\(n\)柱上面都是\(0\),然後此時我們再把剩下\(n\)
最後弄出\(n-1\)個全\(0\)柱和一個全\(1\)柱我們就可以把全一柱去掉然後縮小\(n\)的值。
一直重複到\(n=2\)時我們發現我們的方法不再適用,需要特別處理。
我們按照前面的方法把第一柱分離到\(2\)和\(3\)
然後把\(0\)和\(1\)丟到第一個柱子,然後再把\(1\)丟進第\(3\)個柱子
然後分離第二個柱子就好了
然後這樣就能過了
code
#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; }