dp+矩阵快速幂,CF551D. GukiZ and Binary Operations

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

Problem - 551D - Codeforces


二、解题报告

1、思路分析

今天LATEX怎么不好用了

数据量很大,应该要用O(log) 或者 O(1)的的算法

按位考虑进行dp,计算k每位的方案数累乘即可,详细看下面的LATEX


2、复杂度

时间复杂度: O(L + 8 * log(n)) 空间复杂度:O(L)

3、代码详解

#include <bits/stdc++.h>
using PII = std::pair<int, int>;
using i64 = long long;
using i128 = __int128;
std::ostream& operator<< (std::ostream& out, i128 x) {
    std::string s;
    while (x) s += ((x % 10) ^ 48), x /= 10;
    std::reverse(s.begin(), s.end());
    return out << s;
}

int qp(int a, i64 b, int p) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1LL * res * a % p;
        a = 1LL * a * a % p, b >>= 1;
    }
    return res;
}

int P;
template<typename T>
class Matrix {
private:
    T m, n;
    std::vector<std::vector<T>> g;
public:
    Matrix(int _m, int _n) : m(_m), n(_n), g(m, std::vector<T>(n)) {}
    void init1 () {
        for (int i = 0; i < m; i ++ ) g[i][i] = 1;
    }
    Matrix(const Matrix& x) : m(x.m), n(x.n), g(x.g) {}
    void init (const std::vector<std::vector<T>> _g) {
        g = _g;
    }

    Matrix<T> operator * (const Matrix<T>& x) const {
        Matrix<T> res(m, x.n);
        for (int i = 0; i < m; i ++ )
            for (int k = 0; k < n; k ++ )
                for (int j = 0; j < n; j ++ )
                    res.g[i][j] = (res[i][j] + 1LL * g[i][k] * x[k][j] % P) % P;
        return res;
    }
    const std::vector<T>& operator [] (int i) const {
        return g[i];
    }
    Matrix<T> qp(i64 b) {
        Matrix<T> res(m, n), a(*this);
        res.init1();
        while (b) {
            if (b & 1) res = res * a;
            a = a * a, b >>= 1;
        }
        return res;
    }
};

i64 fib(i64 n) {
    if (n <= 2) return 1; 
    Matrix<i64> a(1, 2) ,b(2, 2);
    std::vector<std::vector<i64>> aa { { 1, 1 } }, bb { { 1, 1 }, { 1, 0 } };
    a.init(aa), b.init(bb);
    
    return (a * b.qp(n - 1))[0][0];
}


void solve() {
    i64 N, K, L, M;
    std::cin >> N >> K >> L >> M;
    P = M;
    if (M == 1 || (L < 63 && 1LL << L <= K)) {
        std::cout << 0;
        return;
    }

    if (L == 0) {
        if (K == 0) std::cout << 1;
        else std::cout << 0;
        return;
    }

    std::vector<int> d(L);
    for (int i = 0; i < L; i ++)
        d[i] = (K >> i & 1);

    i64 f = fib(N + 1), q = ((qp(2, N, M) - f) % M + M) % M, res = 1;

    for (int i = 0; i < L; i ++) {
        if (d[i]) 
            res = res * q % M;
        else 
            res = res * f % M;
    }
    std::cout << res;

}


int main () {
    std::ios::sync_with_stdio(false);   std::cin.tie(0);  std::cout.tie(0);
    int _ = 1;
    // std::cin >> _;
    while (_ --)
        solve();
    return 0;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值