【BZOJ】【1965】SHUFFLE 洗牌
扩展欧几里德+快速幂
每次转换位置:第x位的转移到2*x %(n+1)这个位置上
那么m次后就到了(2^m)*x %(n+1)这个位置上
那么找洗牌m次后在 l 位置上的牌就相当于解线性模方程: (2^m)*x ≡ l (mod n+1) 扩展欧几里得即可
这里扩展欧几里得解的是ax+by=d(mod n+1) 的解,不是等于 l 的……不过只需x*l/d即可~
1 /************************************************************** 2 Problem: 1965 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:0 ms 7 Memory:1272 kb 8 ****************************************************************/ 9 10 //BZOJ 1965 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 using namespace std; 20 int getint(){ 21 int v=0,sign=1; char ch=getchar(); 22 while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();} 23 while(isdigit(ch)) {v=v*10+ch-'0'; ch=getchar();} 24 return v*sign; 25 } 26 /*******************template********************/ 27 typedef long long LL; 28 LL n,m,l,x,y; 29 LL pow(LL x){ 30 LL ans=1,base=2; 31 while(x){ 32 if(x&1) ans=(ans*base)%(n+1); 33 base=base*base%(n+1); 34 x>>=1; 35 } 36 return ans; 37 } 38 void exgcd(LL a,LL b,LL &d,LL &x, LL &y){ 39 if (!b) {d=a; x=1; y=0; return;} 40 else{ exgcd(b,a%b,d,y,x); y-=x*(a/b);} 41 } 42 int main(){ 43 scanf("%lld%lld%lld",&n,&m,&l); 44 LL a=pow(m),b=n+1,d; 45 exgcd(a,b,d,x,y); 46 x=(x*l/d)%b; 47 while(x<0) x+=b; 48 printf("%lld\n",x); 49 return 0; 50 }