• P2054 [AHOI2005]洗牌


    说在前面

    别问,问就是暴力+循环节+O2可以过。

    啊,正解是啥?
    发现对于每次洗牌,原来在第(x)张的牌都翻到了(2x mod(n + 1))。所以,对于第(x)张牌,在经过(m)次洗牌后,变成(x cdot 2^m mod (n + 1))。而最后落在第(L)张的那个,可以列同余方程:

    [x cdot 2 ^ m equiv L pmod{n + 1} ]

    变形,得

    [x equiv L (2^m)^{-1} pmod{n + 1} ]

    用exgcd求出(2^m)(pmod{n + 1})下的逆元后乘上(L)即为所求。

    # include <bits/stdc++.h>
    using namespace std;
    
    long long n,m,L;
    
    void exgcd(long long a,long long b,long long &x,long long &y)
    {
        if(b == 0)
        {
            x = 1,y = 0;
            return;
        }
        exgcd(b,a % b,x,y);
        long long z = x;
        x = y,y = z - (long long)(a / b) * y;
        return;
    }
    
    long long mul(long long x,long long y)
    {
        long long ans = 0;
        while(y)
        {
            if(y & 1) ans = (ans + x) % (n + 1);
            y >>= 1;
            x = (x + x ) % (n + 1);
        }
        return ans % (n + 1);
    }
    
    long long ksm(long long x,long long p)
    {
        x %= (n + 1);
        long long ans = 1;
        while(p)
        {
            if(p & 1) ans = mul(ans,x) % (n + 1);
            p >>= 1;
            x = mul(x,x) % (n + 1);
        }
        return ans % (n + 1);
    }
    
    int main(void)
    {
        scanf("%lld%lld%lld",&n,&m,&L);
        long long x = 0,y = 0;
        exgcd(ksm(2,m),n + 1,x,y);
        if(x < 0) x += (ceil(double(abs(x)) / double(n + 1))) * (n + 1);
        x %= (n + 1);
        printf("%lld
    ",mul(x,L) % (n + 1));
        return 0;
    }
    
  • 相关阅读:
    dart中Map类型详解
    洛谷P1582 倒水(二进制)
    maven依赖 临时转阿里云镜像
    java jdbc 连接数据库
    java 常用类
    java 异常处理
    java 对象 this static 封装
    java 面对对象 内存分析
    团队开发 git
    java 代码块
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/14687409.html
Copyright © 2020-2023  润新知