1. 程式人生 > 實用技巧 >Luogu P3681 [CERC2016]舞動的盤子 Dancing Disks

Luogu P3681 [CERC2016]舞動的盤子 Dancing Disks

法老講課講到的一道妙題,覺得很有趣就寫了下

首先我們觀察題意,發現原問題可以轉化為一個排序問題

考慮我們求出\(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;
}