1. 程式人生 > >【bzoj1965】[Ahoi2005]SHUFFLE 洗牌 - 快速冪

【bzoj1965】[Ahoi2005]SHUFFLE 洗牌 - 快速冪

單行 貢獻 技術分享 print 技術 include data- main alt

為了表彰小聯為Samuel星球的探險所做出的貢獻,小聯被邀請參加Samuel星球近距離載人探險活動。 由於Samuel星球相當遙遠,科學家們要在飛船中度過相當長的一段時間,小聯提議用撲克牌打發長途旅行中的無聊時間。玩了幾局之後,大家覺得單純玩撲克牌對於像他們這樣的高智商人才來說太簡單了。有人提出了撲克牌的一種新的玩法。 對於撲克牌的一次洗牌是這樣定義的,將一疊N(N為偶數)張撲克牌平均分成上下兩疊,取下面一疊的第一張作為新的一疊的第一張,然後取上面一疊的第一張作為新的一疊的第二張,再取下面一疊的第二張作為新的一疊的第三張……如此交替直到所有的牌取完。 如果對一疊6張的撲克牌1 2 3 4 5 6,進行一次洗牌的過程如下圖所示: 技術分享

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

Input

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

Output

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

Sample Input

6 2 3

Sample Output

6
x?(2m)l(mod n+1)x?(2m)≡l(mod n+1)

x在mod n+1下逆元是n/2+1

所以移項得

x(n/2+1)m?l(mod n+1)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;

ll n,m,l;

ll pow(ll x,ll y,ll z)
{
    ll ans=1;x%=z;
    while(y)
    {
        if(y&1) ans=(ans*x)%z;
        x=(x*x)%z;
        y>>=1;
    }
    return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if (!b)
    {
    	x=1,y=0;
    	return a;
	}
	else
	{
		ll fzy=exgcd(b,a%b,x,y);
		ll t=x;x=y,y=t-a/b*y;
		return fzy;
	}
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&l);
    n++;ll a=pow(2,m,n),b=n,x1,y1,g;
    g=exgcd(a,b,x1,y1);
    printf("%lld\n",(x1*(l/g)%(n/g)+(n/g))%(n/g));
}

  

【bzoj1965】[Ahoi2005]SHUFFLE 洗牌 - 快速冪