Codeforces 1182 E. Product Oriented Recurrence(矩阵快速幂 + 欧拉降幂 + 快速幂)

E. Product Oriented Recurrence

Let fx=c2x−6⋅fx−1⋅fx−2⋅fx−3fx=c2x−6⋅fx−1⋅fx−2⋅fx−3 for x≥4x≥4.

You have given integers nn, f1f1, f2f2, f3f3, and cc. Find fnmod(109+7)fnmod(109+7).

Input

The only line contains five integers nn, f1, f2, f3, and c (4≤n≤10184≤n≤1018, 1≤f11≤f1, f2f2, f3f3, c≤109c≤109).

Output

Print fnmod(109+7)

Examples

input

5 1 2 5 3

output

72900

input

17 97 41 37 11

output

317451037

Note

In the first example, f4=90f4=90, f5=72900f5=72900.

In the second example, f17≈2.28×1029587f17≈2.28×1029587.

 

题意:求 fn.

思路:很容易发现对于 f_{1},\ f_{2},\ f_{3} 的指数有规律,设 F_{n} 为 f_{n} 所对应的指数。即当 n >= 7 时  F_{n} = F_{n - 1} + F_{n - 2} + F_{n - 3}

对此,很容易想到矩阵快速幂。即构得初始矩阵a 为:

\begin{pmatrix} 1 &2 &4 \\ 1&2 &3 \\ 1&1 &2 \end{pmatrix},其中 第 1 行 表示 f_{3} 的指数,第 2 行表示 f_{2} 的指数,第 3 行表示 f_{1} 的指数。第一二三列分别代表 n = 4, n = 5, n = 6 时的指数。

对此有 系数矩阵 A:

\begin{pmatrix} 0 &0 &1 \\ 1&0 & 1\\ 0& 1& 1 \end{pmatrix},因此 我们只需要对 A 做矩阵快速幂,然后再与原始矩阵相乘,即可得到 f_{n} 时的 f_{1},\ f_{2},\ f_{3} 的指数。

!!!值得注意的是,由于是对指数做的矩阵快速幂,所以我们需要利用   欧拉降幂   降幂公式,故取模的对象是 phi(1e9 + 7),即 1e9 + 6.

。。。。

剩下的就是 C 的指数,一开始只写了从 n = 4 开始的前面几项,发现指数是 2,6,14,30 还以为是 2^{n + 1} - 2,然后试了一发,连样例都过不了(看来还是我太年轻了),看了题解 ,假设 C 的指数为CM,有:CM_{n} = 2 * n - 6 + CM_{n - 1} + CM_{n - 2}+CM_{n - 3},由于矩阵快速幂需要 是递推式,化简有:

CM_{n} = CM_{n - 1} + CM_{n - 2} + CM_{n - 3} + (n - 3) + (n - 2) - 1      故可得矩阵为

\begin{pmatrix} CM_{n- 1} &CM_{n - 2} &CM_{n - 3} &n - 3 &n - 2 &-1 \end{pmatrix},   推得 系数矩阵 A:

\begin{pmatrix} 1 &1 &0 &0 &0 &0 \\ 1& 0 &1 &0 &0 &0 \\ 1& 0&0 & 0&0 & 0\\ 1& 0& 0& 1 & 0& 0\\ 1& 0& 0 & 0 & 1& 0\\ 1&0 & 0&-1 & -1 &1 \end{pmatrix},然后利用相同的方式求得 C 的指数。

Code:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const LL mod = 1e9 + 7;
const LL phip = 1e9 + 6;
const int maxn = 8;

struct mat{
    LL m[maxn][maxn];
};

mat cal(mat A,mat B,int n){
    mat C;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= n;j ++){
            C.m[i][j] = 0;
            for(int x = 1;x <= n;x ++){
                C.m[i][j] = ((A.m[i][x] * B.m[x][j]) % phip + C.m[i][j]) % phip;
            }
        }
    return C;
}

mat quick_mat(mat A,LL coun,int n){
    mat C;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= n;j ++)
            C.m[i][j] = (i == j);
    while(coun > 0){
        if(coun & 1) C = cal(C,A,n);
        A = cal(A,A,n);
        coun >>= 1;
    }
    return C;
}

LL quick_pow(LL a,LL b){
    LL ans = 1;
    while(b){
        if(b & 1) (ans *= a) %= mod;
        (a *= a) %= mod;
        b >>= 1;
    }
    return ans;
}

LL cal_cimiC(LL x){
    mat a; clr(a.m,0);
    a.m[1][1] = 14; a.m[1][2] = 6;
    a.m[1][3] = 2;  a.m[1][4] = 4;
    a.m[1][5] = 5;  a.m[1][6] = -1;
    if(x <= 6){
        return x == 6 ? a.m[1][1] : (x == 5 ? a.m[1][2] : a.m[1][3]);
    }
    mat A; clr(A.m,0);
    A.m[1][1] = A.m[2][1] = A.m[3][1] = A.m[4][1] = A.m[5][1] = A.m[6][1] = 1;
    A.m[1][2] = A.m[2][3] = A.m[4][4] = A.m[5][5] = A.m[6][6] = 1;
    A.m[6][4] = A.m[6][5] = -1;
    A = quick_mat(A,x - 6,6);
    a = cal(a,A,6);
    return a.m[1][1];
}

int main() {
    LL x,f1,f2,f3,c;
    while(cin >> x >> f1 >> f2 >> f3 >> c){
        mat a;
        a.m[1][1] = 1; a.m[1][2] = 2; a.m[1][3] = 4;
        a.m[2][1] = 1; a.m[2][2] = 2; a.m[2][3] = 3;
        a.m[3][1] = 1; a.m[3][2] = 1; a.m[3][3] = 2;
        LL cimi_c = cal_cimiC(x);
//        debug(cimi_c);
        LL F1,F2,F3;
        if(x <= 6){
            F1 = quick_pow(f1,a.m[3][x - 3]);
            F2 = quick_pow(f2,a.m[2][x - 3]);
            F3 = quick_pow(f3,a.m[1][x - 3]);
            cout << quick_pow(c,cimi_c) * F1 % mod * F2 % mod * F3 % mod << endl;
            continue;
        }
        mat A;
        A.m[1][1] = 0; A.m[1][2] = 0; A.m[1][3] = 1;
        A.m[2][1] = 1; A.m[2][2] = 0; A.m[2][3] = 1;
        A.m[3][1] = 0; A.m[3][2] = 1; A.m[3][3] = 1;
        A = quick_mat(A,x - 6,3);
        a = cal(a,A,3);
        F1 = quick_pow(f1,a.m[3][3]);
        F2 = quick_pow(f2,a.m[2][3]);
        F3 = quick_pow(f3,a.m[1][3]);
        cout << quick_pow(c,cimi_c) * F1 % mod * F2 % mod * F3 % mod << endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值