YCOJ 洗牌

描述

爲了表彰小聯爲Samuel星球的探險所作出的貢獻,小聯被邀請參加Samuel星球近距離載人探險活動。 因爲Samuel星球至關遙遠,科學家們要在飛船中度過至關長的一段時間,小聯提議用撲克牌打發長途旅行中的無聊時間。玩了幾局以後,你們以爲單純玩撲克牌對於像他們這樣的高智商人才來講太簡單了。有人提出了撲克牌的一種新的玩法。html

對於撲克牌的一次洗牌是這樣定義的,將一疊N(N爲偶數)張撲克牌平均分紅上下兩疊,取下面一疊的第一張做爲新的一疊的第一張,而後取上面一疊的第一張做爲新的一疊的第二張,再取下面一疊的第二張做爲新的一疊的第三張……如此交替直到全部的牌取完。 若是對一疊6張的撲克牌1 2 3 4 5 6,進行一次洗牌的過程以下圖所示:c++

img

從圖中能夠看出通過一次洗牌,序列1 2 3 4 5 6變爲4 1 5 2 6 3。固然,再對獲得的序列進行一次洗牌,又會變爲2 4 6 1 3 5。 遊戲是這樣的,若是給定長度爲N的一疊撲克牌,而且牌面大小從1開始連續增長到N(不考慮花色),對這樣的一疊撲克牌,進行M次洗牌。最早說出通過洗牌後的撲克牌序列中第L張撲克牌的牌面大小是多少的科學家得勝。小聯想贏取遊戲的勝利,你能幫助他嗎?web

 

輸入 (讀取文件: shuffle.in)

 

有三個用空格間隔的整數,分別表示N,M,L (其中0< N ≤ 10 ^ 10 ,0 ≤ M ≤ 10 ^ 10,且N爲偶數)。spa

 

輸出 (寫入文件: shuffle.out)

 單行輸出指定的撲克牌的牌面大小code

輸入樣例 1 

 

6 2 3

 

輸入樣例 1 

6

解題思路

  咱們先手動模擬一下這副牌(以8爲例):htm

 

咱們每次洗牌,又把牌分紅兩部分,咱們來找找規律(設一張牌的位置爲x)blog

  前一部分牌,下一次都會到2*x的位置遊戲

  後一部分牌,下一次都會到(x-n/2)*2-1的位置ci

  由於他給咱們的是洗完m次牌後的位置l,因此咱們只需倒推便可it

  可是怎麼知道當前這張牌是由那一部分推過來的呢?

  再回頭看看規律,你就知道,從前一部分洗來的牌都是偶數位置,後一部分洗來的牌都是奇數位置,因此只要判斷當前位置的奇偶性遞推就好了,可是看看數據大小,確定要超時啊,但他洗牌不管洗多少次,總有一個循環節,咱們求出循環節的長度,m對長度取模輸出,就不用去模擬了。

題解

 

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll n,m,l;
 5 ll flag[10000001];//記錄循環節中第i次洗牌後的位置ai 
 6 ll ans=1;
 7 int main()
 8 {
 9     cin>>n>>m>>l;
10     flag[0]=l;
11     while(1)
12     {
13         if(l%2==0)//從前半部分推來的 
14         {
15             l/=2;
16         }
17         else//後半部分 
18         {
19             l=(l+1)/2+n/2;
20         }
21         if(l==flag[0])break;//重複了,循環節就找完了 
22         flag[ans]=l;
23         ans++;
24     }
25     m%=ans;//取模 
26     cout<<flag[m]<<endl;
27     //輸出洗完m次牌後當前位置的數 (由於從有序開始洗的牌,因此位置就是牌的編號) 
28 }
相關文章
相關標籤/搜索