2019.8.1 牛客多校第五场

index > 牛客多校第五场


题号标题通过率做法状态
Adigits 21017/2383签到√+
Bgenerator 1555/3660矩阵快速幂/十进制优化
Cgenerator 237/626
Dgenerator 34/23
Eindependent set 145/110
Fmaximum clique 193/838
Gsubsequence 1522/2513dp√-
Hsubsequence 2286/1366
Ithree points 1139/2701
Jthree points 27/76
  • 代表赛后补题
  • √+ 代表赛内我通过的
  • √- 代表赛内不是我做的
  • √-○代表赛内不是我做的,补了

A - digits 2

好像我们脑子也不是转得很快,所以还是废了点功夫才想到拼接。

B - generator 1

比赛时莫名其妙地以为,矩阵乘法也可以欧拉降幂。然后从头wa到结束。

其实用了一个很巧妙的想法。

题意就是给一个公式(显然是用二维矩阵快速幂求的)。然后给你一个无比庞大的n( 1 0 1000000 10^{1000000} 101000000)。但是个数存不下来,转二进制又非常麻烦。

那么咋办?可以直接用十进制来做呀,我们回顾一下二进制快速幂就是取二进制每一位是1的时候,把乘幂处理好的底数乘上去。由于二进制每位只有两个选择,所以比较简单。

十进制也完全可以处理底数 b a s e = b a s e 10 base = base^{10} base=base10,但是二进制每一位还有9个选择,那也好办,如果这一位是 x x x r e s = r e s × ( b a s e 10 ) x res =res \times (base^{10})^{x} res=res×(base10)x

这样的每次乘幂的次数就降低到 10 10 10以下了,这个乘幂还是有必要二进制快速幂一下,这题卡这个是严了一点。但是这样也避免了全局转二进制太麻烦,而且复杂度也不至于太高。

#define _debug(x) cerr<<#x<<" = "<<x<<endl

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;


template<typename _Tp, const int MAXMatrixSize>
struct Matrix {
    _Tp m[MAXMatrixSize][MAXMatrixSize];
    _Tp mod = 0;

    Matrix() {
        memset(m, 0, sizeof m);
    }

    Matrix(int _mod) : mod(_mod) {
        memset(m, 0, sizeof m);
    }

    void init1() {
        //*this = Matrix(mod);
        set(0, 0, 1);
        set(1, 1, 1);
//        for (int i = 0; i < MAXMatrixSize; i++)
//            m[i][i] = 1;
    }

    inline void set(const int &r, const int &c, const _Tp &v) { this->m[r][c] = v; }

    inline _Tp get(const int &r, const int &c) { return this->m[r][c]; }

    inline void setMod(const _Tp &_mod) { this->mod = _mod; }

    inline Matrix operator*(const Matrix t) {
        Matrix res(mod);//= Matrix(mod);
        res.setMod(mod);
        for (int i = 0; i < MAXMatrixSize; i++)
            for (int j = 0; j < MAXMatrixSize; j++)
                for (int k = 0; k < MAXMatrixSize; k++)
                    res.m[i][j] = (res.m[i][j] + m[i][k] * t.m[k][j]) % mod;
        return res;
    }
};

typedef Matrix<ll, 2> mat;

mat A, B;
ll x0, x1, a, b;
ll mo, len;
char n[1000059];

inline mat fpow(mat base, ll exp) {
    mat res(mo);
    res.init1();
    while (exp) {
        if (exp & 1)res = res * base;
        exp >>= 1;
        base = base * base;
    }
    return res;
}

inline ll calc() {

    len = strlen(n);
    //reverse(n, n + len);

    mat res(mo);
    res.init1();
    mat base = B;

    for (int i = len - 1; i >= 0; --i) {
        if (n[i] > '0')
            res = res * fpow(base, n[i] - '0');
        base = fpow(base, 10);
    }

    res = A * res;
    return res.get(0, 0);
}


int main() {

    scanf("%lld%lld%lld%lld", &x0, &x1, &a, &b);
    scanf("%s %lld", n, &mo);

    A = mat(mo);
    A.set(0, 0, x0);
    A.set(0, 1, x1);

    B = mat(mo);
    B.set(0, 0, 0);
    B.set(0, 1, b);
    B.set(1, 0, 1);
    B.set(1, 1, a);

    printf("%lld\n", calc());
    return 0;
}
/*




 * */
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值