来个正常的有证明的题解
我们不好来表示某时刻某一个位置是哪一张牌,但我们可以表示某时刻某一张牌在哪个位置。
设数列({a_{i_j}})表示(i)号牌经过(j)次洗牌后的位置,我们试着来递推一下
首先,如果此刻牌在上面一叠,显然(a_{i_{j+1}}=2a_{i_j})
接着,如果这张牌在下面一叠,那么(a_{i_{j+1}}=2(a_{i_j}-frac n2)-1=2a_{i_j}-(n+1)),应该也很好推出来
写在一起,观察一下
[a_{i_{j+1}}=egin{cases}2a_{i_j}qquadqquad ,a_{i_j}leqfrac n2\2a_{i_j}-(n+1),a_{i_j}>frac n2end{cases}
]
诶,两个式子都有一个系数(2)呢!那我们可不可以把它看成模(n+1)意义下的结果呢?
于是可以进一步得到(a_{i_j}equiv2^mi(mod n+1))((i)就是(a_{i_0}))
题目已经知道了(a_{i_j}),来求(i),不就是一个线性同余不定方程么?exgcd搞一下就好啦!因为(gcd(2^m,n+1)=1),所以根本不用像青蛙的约会那样麻烦。
看楼上大佬用异或写swap?!第一次见的蒟蒻表示只能Orz。然后蒟蒻就把exgcd这个函数成功压缩到了一行。。。。。。
#include<cstdio>
#define LL long long
LL n,m,l,x=1,y;
LL qpow(LL b,LL k){//快速幂求2^m
LL a=1;
while(k){
if(k&1)a*=b,a%=n+1;
b*=b,b%=n+1;
k>>=1;
}
return a;
}
void exgcd(LL a,LL b){//一行exgcd233
if(b)exgcd(b,a%b),(y^=x^=y^=x)-=a/b*x;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&l);
exgcd(qpow(2,m),n+1);
printf("%lld
",(l*x%(n+1)+n+1)%(n+1));//注意化成最小正整数
return 0;
}