[BZOJ1965][Ahoi2005]SHUFFLE 洗牌(数学相关)

来源:互联网 发布:mac 命令行上传文件 编辑:程序博客网 时间:2024/05/30 19:33

题目描述

传送门

题解

每一次洗牌:
对于i<=n2i>2i
对于i>n2i>(in21)2+1=2i(n+1)
所以对于所有的ii>2i%(n+1)
m次牌之后,i>2m%(n+1)
那么洗m次牌之后位置是l的话,它最初的位置应该是l2m(modn+1)
扩欧求逆元,并且用快速乘防止炸long long

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define LL long longLL n,m,l,ans;LL fast_mul(LL a,LL p){    LL ans=0LL;    for (;p;p>>=1LL,a=(a+a)%(n+1))        if (p&1)            ans=(ans+a)%(n+1);    return ans;}LL fast_pow(LL a,LL p){    LL ans=1LL;    for (;p;p>>=1LL,a=fast_mul(a,a)%(n+1))        if (p&1LL)            ans=fast_mul(ans,a)%(n+1);    return ans;}void exgcd(LL a,LL b,LL &x,LL &y){    if (!b) x=1LL,y=0LL;    else exgcd(b,a%b,y,x),y-=a/b*x;}LL inv(LL a,LL b){    LL x=0LL,y=0LL;    exgcd(a,b,x,y);    x=(x%b+b)%b;    if (!x) x+=b;    return x;}int main(){    scanf("%lld%lld%lld",&n,&m,&l);    ans=fast_mul(l%(n+1),inv(fast_pow(2LL,m),n+1))%(n+1);    printf("%lld\n",ans);}
0 0