CF1182E 题解

前言

题目传送门!

更好的阅读体验?

zlt 推荐矩阵加速题目。其实很不算难啊,不就是模拟吗。

思路

首先乘法是不能用矩阵加速直接维护的,考虑答案为 fn=ck1×f1k2×f2k3×f3k4

这些都是可以转移的。

对于 c指数的转移:(ti2,ti1,ti,2i6,1) 分别表示最近的三项(fi2,fi1,fi)的 c 的指数、以及一些常数。

fi+1=c2i6×fi×fi1×fi2

对应的指数 ki+1=2(i+1)6+ki+ki1+ki2

矩阵转移:

(ti2ti1ti2i61)×(0010010100011000011000221)=(ti1titi+12(i+1)61)


对于 f1指数的转移:{ti2,ti1,ti} 分别表示最近的三项(fi2,fi1,fi)的 f1 的指数。

fi+1=c2i6×fi×fi1×fi2

对应的指数 ki+1=ki+ki1+ki2

矩阵转移:

(ti2ti1ti)=(001101011)×(ti1titi+1)


对于 f2f3 的指数转移,矩阵转移是与 f1 的相同的。

仅仅是初始化不同。


三者对应的指数就是第 3 项,这个自己对上即可。

最后再上快速幂即可求出。

代码

不喜欢用重载(次次考场都不会写重载格式),所以代码看起来会很长。

代码其实不用放的,抄一遍上面的矩阵即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int mod = 1e9 + 7;
typedef long long ll;

namespace martix_3 { //矩阵快速幂,懂的直接忽略即可
    void mul(int ANS[][3], int x[][3], int y[][3])
    {
        int ans[3][3] = {};
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                for (int k = 0; k < 3; k++)
                    ans[i][j] = (ans[i][j] + 1ll * x[i][k] * y[k][j]) % (mod - 1);
        memcpy(ANS, ans, sizeof ans);
    }
    void ksm(int f[][3], int a[][3], ll y)
    {
        while (y)
        {
            if (y & 1) mul(f, f, a);
            mul(a, a, a);
            y >>= 1;
        }
    }
};
namespace martix_5 { //矩阵快速幂,懂的直接忽略即可
    void mul(int ANS[][5], int x[][5], int y[][5])
    {
        int ans[5][5] = {};
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                for (int k = 0; k < 5; k++)
                    ans[i][j] = (ans[i][j] + 1ll * x[i][k] * y[k][j]) % (mod - 1);
        memcpy(ANS, ans, sizeof ans);
    }
    void ksm(int f[][5], int a[][5], ll y)
    {
        while (y)
        {
            if (y & 1) mul(f, f, a);
            mul(a, a, a);
            y >>= 1;
        }
    }
};
int qpow(int x, int y) //快速幂,懂的直接忽略即可
{
    int ans = 1;
    while (y)
    {
        if (y & 1) ans = (1ll * ans * x) % mod;
        x = (1ll * x * x) % mod;
        y >>= 1;
    }
    return ans;
}
int main()
{
    ll n; int f1, f2, f3, c;
    cin >> n >> f1 >> f2 >> f3 >> c;

    int getc_f[5][5] = {0, 0, 0, 0, 1}; //i=3,算c
    int getc_a[5][5] = {
        0, 0, 1, 0, 0,
        1, 0, 1, 0, 0, 
        0, 1, 1, 0, 0,
        0, 0, 1, 1, 0,
        0, 0, 2, 2, 1
    };
    martix_5::ksm(getc_f, getc_a, n - 3);
    int c_k = getc_f[0][2];

    int getf1_f[3][3] = {1, 0, 0}; //i=3,算f1
    int getf1_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf1_f, getf1_a, n - 3);
    int f1_k = getf1_f[0][2];

    int getf2_f[3][3] = {0, 1, 0}; //i=3,算f2
    int getf2_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf2_f, getf2_a, n - 3);
    int f2_k = getf2_f[0][2];

    int getf3_f[3][3] = {0, 0, 1}; //i=3,算f3
    int getf3_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf3_f, getf3_a, n - 3);
    int f3_k = getf3_f[0][2];

    //printf("f_n = c^%d * f1^%d * f2^%d * f3^%d\n", c_k, f1_k, f2_k, f3_k);
    int ans = 1;
    ans = 1ll * ans * qpow(c, c_k) % mod;
    ans = 1ll * ans * qpow(f1, f1_k) % mod;
    ans = 1ll * ans * qpow(f2, f2_k) % mod;
    ans = 1ll * ans * qpow(f3, f3_k) % mod;
    cout << ans;
    return 0;
}

希望能帮助到大家!

posted @   liangbowen  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示