1. 程式人生 > 實用技巧 >[AHOI2005]洗牌

[AHOI2005]洗牌

https://www.luogu.com.cn/problem/P2054

設 n=2m
為了方便進行有關剩餘系的推導
把原本的標號1.....2m
改為0......2m-1

發現原本在位置x的牌
經過

#include<bits/stdc++.h>
#define N 110000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
inline ll read()
{
	char ch=0;
	ll x=0,flag=1;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
	return x*flag;
}
ll mo;
ll ksc(ll x,ll y,ll p){return ((x*y-(ll)(((ldb)x*y+0.5)/p)*p)%p+p)%p;}
ll ksm(ll x,ll k)
{
	ll ans=1;
	while(k)
	{
		if(k&1)ans=ksc(ans,x,mo);
		k>>=1;x=ksc(x,x,mo);
	}
	return ans;
}
ll X,Y;
ll exgcd(ll a,ll b)
{
	if(!b){X=1;Y=0;return a;}
	ll d=exgcd(b,a%b),t=X;
	X=Y;Y=t-(a/b)*Y;
	return d; 
}
int main()
{
	ll n=read(),m=read(),l=read();mo=n+1;
	ll a=ksm(2,m),b=mo,d=exgcd(a,b),p1=b/d;
	X=(X%p1+p1)%p1;X=ksc(X,(l/d),p1);
	printf("%lld",X);
	return 0;
}