http://www.lydsy.com/JudgeOnline/problem.php?id=1965
各位神犇都不写水题的解题报告,那就我这种弱菜来写吧。
知识储备:扩展gcd的应用及简单同余方程解法。
大意:一开始1~n(2|n)牌依次排列,每次分成等量前后两份,按后1-前1-后2-前2……的顺序依次重新排列,已知牌数N,洗牌次数M,洗牌后扑克牌在第L张,求一开始L的位置。
解法:设Ai表示第i次洗牌后要求的扑克牌的位置,显然A0即为所求。
建立简洁的关系式(一定要简洁,之前的分块做法不方便总结),得Ai=2(Ai-1) mod (N+1)
由迭代及mod的简并性得Am=2m*A0 mod (N+1)。该式Am=L,2m已知,解同余方程A0*2m=Am(mod N+1)即可,此式可用2m mod (N+1)替换2m,用快速幂计算即可,注意不能用sqr防止溢出。
program shuffle; var n,m,l,x,y:int64; Function times(pa,pb,pc:int64):int64;//快速幂 begin if pb=0 then exit(1); if pb=1 then exit(pa mod pc); times:=times(pa,pb shr 1,pc); times:=times*times mod pc;//不能用sqr! if odd(pb) then times:=((times mod pc)*pa) mod pc; end; Function ExGcd(a,b:int64):int64;//计算A*x+B*y=Gcd(a,b)的一个(x,y) var oldx:int64; begin if b=0 then begin x:=1; y:=0; exit; end; Exgcd(b,a mod b); oldx:=x; x:=y; y:=oldx-a div b*y; end; Function solve(a,b,c:int64):int64;//Ax=B(mod C) 则 Ax-Cy=b,用Exgcd解这个方程得到(x,y) begin Exgcd(a,c); x:=x mod c; if x<0 then inc(x,c); x:=x*b mod c; end; begin readln(n,m,l); writeln(solve(Times(2,m,n+1),l,n+1)); end.