[递推+矩阵快速幂]Codeforces 1117D - Magic Gems

Posted fanwl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[递推+矩阵快速幂]Codeforces 1117D - Magic Gems相关的知识,希望对你有一定的参考价值。

传送门:Educational Codeforces Round 60 – D

 

题意:

给定N,M(n <1e18,m <= 100)

一个magic gem可以分裂成M个普通的gem,现在需要N个gem,可以选择一定的magic gem,指定每一个分裂或不分裂,问一共有多少种方案

两种分裂方案不同当且仅当magic gem的数量不同,或者分裂的magic gem的索引不同。

思路:

1.首先从dp的角度出发

  设F(i)为最终需要i个gem的方案数,容易得到递推式:

技术图片

  (总方案数 = 最右边的magic gem分裂得到的方案数 + 最右边的magic gem不分裂得到的方案数)

2.观察数据范围可以看到,如果直接这样计算,时间复杂度是要上天的

  我们可以把递推式求解转化成矩阵乘法求解

  技术图片

3.套用矩阵快速幂的板子,加速计算

参考代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define _____ ios::sync_with_stdio(false);cin.tie(0);
const int M = 1e9 + 7;
//head

ll n,m;
struct Mat{
    ll a[102][102];
};
Mat mul(const Mat & a,const Mat & b){
    Mat ans;
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            ans.a[i][j] = 0;
            for(int k = 1; k <= m; k++){
                ans.a[i][j] += a.a[i][k]*b.a[k][j];
                if(ans.a[i][j] > M)ans.a[i][j] %= M;
            }
        }
    }
    return ans;
}
Mat quick_pow(Mat a,ll b){
    Mat t;
    for(int i = 1; i <= m; i++)t.a[i][i] = 1;
    while(b){
        if(b & 1)t = mul(t,a);
        b >>= 1;
        a = mul(a,a);
    }
    return t;
}
int main(){
    //freopen("data.in","r",stdin);
    _____
    cin >> n >> m;
    if(n < m){cout << 1 << 
;}
    else{
        Mat ans,t;
        for(int i = 1; i < m; i++){
            ans.a[i+1][i] = 1;
        }
        ans.a[1][m] = ans.a[m][m] = 1;
        ans = quick_pow(ans,n-m);
        Mat a;
        for(int i = 1; i < m; i++)a.a[1][i] = 1;
        a.a[1][m] = 2;
        a = mul(a,ans);
        cout << a.a[1][m] << 
;
    }
    return 0;
}

 

以上是关于[递推+矩阵快速幂]Codeforces 1117D - Magic Gems的主要内容,如果未能解决你的问题,请参考以下文章

hdu 2604 递推 矩阵快速幂

浅谈矩阵快速幂

矩阵快速幂递推+欧拉降幂

HDU Queuing (递推+矩阵快速幂)

Happy Necklace (矩阵快速幂 + 递推 + 取模)

HDU - 6185 Covering(暴搜+递推+矩阵快速幂)