Luogu P3681 [CERC2016]舞動的盤子 Dancing Disks
阿新 • • 發佈:2020-07-21
法老講課講到的一道妙題,覺得很有趣就寫了下
首先我們觀察題意,發現原問題可以轉化為一個排序問題
考慮我們求出\(f_{i,j}\)表示在\((i,j)\)格子上,最多可以保證頂上的\(f_{i,j}\)個數有序
考慮對於所有的\((i',j'),i'\in[1,i],j'\in[1,j],i'\not =i\or j'\not= j\),利用多路歸併的思想,這上面的盤子都可以擺到\((i,j)\)上
換句話說就是\(f_{x,y}=\sum_{i=1}^x\sum_{j=1}^y f_{i,j} (i\not =x\or j\not= y)\)
然後\(f_{6,6}\)上就是最後能排好序的盤子數目了,我們打個表看看:
woc好像不行的亞子,難道就這樣GG了?
我們再仔細想一下,其實對於\(f_{1,2}\)和\(f_{2,1}\),它們其實是可以通過討論來做到\(f_{1,2}=f_{2,1}=2\)的,這樣一來還是按照上面的式子我們算一算:
和資料範圍完美契合,可以通過此題
然後稍微講下實現吧,首先我們肯定是考慮遞迴完成這個問題,設一個函式solve(x,y,tp)
表示做到\((x,y)\)且這個位置上要放成升序還是降序
至於為什麼要升降序,因為考慮我們歸併的時候由於每個格子相當於是一個棧,因此之前的格子的升降序就要與後面的相反
然後多路歸併的話就直接用堆來維護即可,有一些小細節
總複雜度應該是\(O(6^6+36\times n\times \log 36)\)
#include<cstdio> #include<utility> #include<queue> #include<stack> #include<iostream> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second using namespace std; typedef pair <int,int> pi; typedef pair <int,pi> ipi; const int N=10; priority_queue <ipi,vector<ipi>,less<ipi> > big; priority_queue <ipi,vector<ipi>,greater<ipi> > small; stack <int> A[N][N],B[N][N]; int n,x; inline void move(const pi& A,const pi& B) //move the top disk of A to B { int x=A.fi; while (x<B.fi) printf("%d %d D 1\n",x++,A.se); int y=A.se; while (y<B.se) printf("%d %d R 1\n",x,y++); } inline void sort_greater(CI x,CI y) { for (RI i=1,j;i<=x;++i) for (j=1;j<=y;++j) if ((i!=x||j!=y)&&!A[i][j].empty()) big.push(mp(A[i][j].top(),mp(i,j))); while (!big.empty()) { pi nw=big.top().se; A[x][y].push(big.top().fi); big.pop(); move(nw,mp(x,y)); if (A[nw.fi][nw.se].pop(),!A[nw.fi][nw.se].empty()) big.push(mp(A[nw.fi][nw.se].top(),nw)); } } inline void sort_less(CI x,CI y) { for (RI i=1,j;i<=x;++i) for (j=1;j<=y;++j) if ((i!=x||j!=y)&&!A[i][j].empty()) small.push(mp(A[i][j].top(),mp(i,j))); while (!small.empty()) { pi nw=small.top().se; A[x][y].push(small.top().fi); small.pop(); move(nw,mp(x,y)); if (A[nw.fi][nw.se].pop(),!A[nw.fi][nw.se].empty()) small.push(mp(A[nw.fi][nw.se].top(),nw)); } } inline void solve(int x,int y,bool tp) // tp=0 less otherwise greater { if (x==1&&y==1) { if (!B[x][y].empty()) A[x][y].push(B[x][y].top()),B[x][y].pop(); return; } if ((x==1&&y==2)||(x==2&&y==1)) { if (B[1][1].empty()) return; int a=B[1][1].top(); B[1][1].pop(); if (B[1][1].empty()) return A[x][y].push(a),move(mp(1,1),mp(x,y)); int b=B[1][1].top(); B[1][1].pop(); if ((a>b)^tp) printf("%d %d %c 2\n",1,1,x==1?'R':'D'); else printf("%d %d %c 1\n%d %d %c 1\n",1,1,x==1?'R':'D',1,1,x==1?'R':'D'); if (tp) A[x][y].push(max(a,b)),A[x][y].push(min(a,b)); else A[x][y].push(min(a,b)),A[x][y].push(max(a,b)); return; } for (RI i=x,j;i;--i) for (j=y;j;--j) if (i!=x||j!=y) solve(i,j,tp^1); if (tp) sort_greater(x,y); else sort_less(x,y); } int main() { scanf("%d",&n); for (RI i=1;i<=n;++i) scanf("%d",&x),B[1][1].push(x); return solve(6,6,1),0; }