題意:我們要利用n張牌表演一個魔術,魔術的步驟是這樣的:
將開頭一張牌移動到最後,接著拿出這堆牌的第一張,這張牌的數字是1,將這張牌丟棄
將開頭二張牌移動到最後,接著拿出這堆牌的第一張,這張牌的數字是2,將這張牌丟棄
將開頭三張牌移動到最後,接著拿出這堆牌的第一張,這張牌的數字是3,將這張牌丟棄
……
將開頭n張牌移動到最後,接著拿出這堆牌的第一張,這張牌的數字是n
問你,假如要成功地表演這個魔術,我們要將這n張牌排成什麼樣子?請輸出這個排列。
分析:一道簡單的模擬題。一開始就有一個直觀想法,枚舉14個數字的全排列,然後依次模擬,判斷哪一個解是符合魔術步驟的,輸出它。但是我算了一下,14個數字的全排列是:87178291200,很明顯,枚舉必定超時。這題其實是要用逆向思維,首先我們必須明確一點,那就是:第一張牌一定在牌堆的第二個位置。其實這就是此題的突破口:每張牌的所在位置都是根據上一個狀態推出的。讓我來舉個例子,對於樣例n=4,模擬的過程就是:
設第一張牌的數字是x1,第二張牌為x2,第三張牌為x3,第四張牌為x4
當前牌堆序列為:x1 x2 x3 x4
將第一張牌移到最後,原序列為: x2 x3 x4 x1,也就是說x2一定是1
刪除x2,繼續模擬,將前兩張牌移動到最後,原序列為:x1 x3 x4,也就是說x1一定是2
以此類推,我們可以還原出整個序列:2 1 4 3。
我使用了deque(雙端隊列)來模擬整個過程,因為雙端隊列支持pop_front和push_front,比較方便。
代碼(0ms AC):
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,t,ans[20];
void solve(){
deque Q;
for(int i=1;i<=n;i++)
Q.push_back(i);
int s=1;
while(!Q.empty()){
for(int i=1;i<=s;i++){
int x=Q.front();
Q.pop_front();
Q.push_back(x);
}
ans[Q.front()]=s++;
Q.pop_front();
}
for(int i=1;i<=n;i++)
if(i!=n)
printf("%d ",ans[i]);
else printf("%d\n",ans[i]);
}
int main()
{
scanf("%d",&t);
while(t>=1){
scanf("%d",&n);
solve();
}
//system("pause");
return 0;