[AHOI2005]洗牌(线性同余方程)

这题的关键在于怎么建模。把已知信息建成数学模型再来解答。


通过打表或者其他方法找规律得到在位置x通过一次变换得到的位置是$x \times 2$ % $n+1$。

m次即为$2^{m}x \equiv l(\mod n+1)$。找到这个线性同余方程的解就是答案。

直接乘会爆longlong所以要用龟速乘或long double。

#include 

#include 

typedef long long ll;

using namespace std;

ll n, m, l;

ll exgcd(ll a, ll b, ll &x, ll &y) {

    if (b == 0) {

        x = 1;

        y = 0;

        return a;

    }

    ll g = exgcd(b, a % b, y, x);

    y -= a / b * x;

    return g;

}

ll mul(ll a, ll b, ll mod) {

    ll ret = 0;

    while (b) {

        if (b & 1) ret = (ret + a) % mod;

        a = (a + a) % mod;

        b >>= 1;

    }

    return ret;

}

ll ksm(ll a, ll b, ll mod) {

    ll ret = 1;

    while (b) {

        if (b & 1) ret = mul(ret, a, mod);

        a = mul(a, a, mod);

        b >>= 1;

    }

    return ret;

}



int main() {

    ll x0, y0;

    cin >> n >> m >> l;

    exgcd(ksm(2, m, n + 1), n + 1, x0, y0);

    x0 = (x0 % (n + 1) + n + 1) % (n + 1);

    x0 = mul(x0, l, n + 1);

    cout << x0;

    return 0;

}

 

你可能感兴趣的:([AHOI2005]洗牌(线性同余方程))