一道簡單的遞推題(快速冪+矩陣乘法優化+滾動數組)

問題 F: 一道簡單的遞推題

時間限制: 1 Sec  內存限制: 128 MB
提交: 546  解決: 48
[提交][狀態][討論版]

題目描述

存在以下遞推式:
F(n+1)=A1*F(n)+A2*F(n-1)+...+An*F(1)
求第K項的值對1000000007取模的結果

輸入

單組測試數據php

第一行輸入兩個整數 n , k (1<=n<=100,n<k<=10000000000)ios

第二行輸入 n 個整數 F(1)   F(2)   ...   F(n)數組

第三行輸入 n 個整數A1   A2   ...   An 函數

輸出

輸出一個整數學習

樣例輸入

2   3
1   2
3   4

樣例輸出

10


今天作這個題,發現這個題真乃卡時間的神題...讓我學到了不少..
- 第一個是我像平時同樣上快速冪的模板,返回一個矩陣結構體,可是我發現連跑都跑不了 = =,後面發現是因爲矩陣結構體內開了一個 200*200 的二維數組,二函數返回不了這麼大空間的結構體,
我開始一直覺得玄學,一直改一直改,改了1個多小時,後來把常量改爲 100,沒想到就能夠跑了,居然是這個緣由,又學習到一個!

- 第二個是我改了以後AC不了,一直提醒時間超限,而後羣裏dalao教我新姿式:優化的矩陣乘法和滾動數組.
Matrix mult(Matrix a,Matrix b,int n)
{
    Matrix temp;
    for(int i=0; i<n; i++)
    {
        for(int k=0; k<n; k++)
        {
            if(a.v[i][k] == 0 ) continue;
            for(int j=0; j<n; j++)
            {
                temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
            }
        }
    }
    return temp;
}

之前的:測試

Matrix mult(Matrix a,Matrix b,int n){
    Matrix temp;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            for(int k=0;k<n;k++){
                temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
            }
        }
    }
    return temp;
}

這個技巧十分有用!特別是當矩陣高階而且稀疏的時候~優化

滾動數組的優化就真的玄學了...我也不知道爲何快..ui

這個題的係數矩陣是:spa

A1 A2 ... AN
1   0    ... 0
0   1   ...  0
         ....
0 0     ... 1 0

AC代碼:指針

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const LL mod = 1000000007;
const int N = 102;
LL f[N];
struct Matrix
{
    LL v[N][N];
    Matrix()
    {
        memset(v,0,sizeof(v));
    }
} M[2];
Matrix mult(Matrix a,Matrix b,int n)
{
    Matrix temp;
    for(int i=0; i<n; i++)
    {
        for(int k=0; k<n; k++)
        {
            if(a.v[i][k] == 0 ) continue;
            for(int j=0; j<n; j++)
            {
                temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod;
            }
        }
    }
    return temp;
}
void pow_mod(LL t,LL n)
{
    for(int i=0; i<n; i++)
    {
        M[0].v[i][i] = 1;
    }
    while(t)
    {
        if(t&1) M[0] = mult(M[0],M[1],n);
        M[1] = mult(M[1],M[1],n);
        t>>=1;
    }
}
int main()
{
    int n;
    LL k;
    scanf("%d%lld",&n,&k);
    for(int i=0; i<n; i++)
    {
        scanf("%lld",&f[n-1-i]);
    }
    for(int i=0; i<n; i++)
    {
        scanf("%lld",&M[1].v[0][i]);
    }
    for(int i=1; i<n; i++)
    {
        M[1].v[i][i-1] = 1;
    }
    k = k-n;
    pow_mod(k,n);
    LL ans = 0;
    for(int i=0; i<n; i++)
    {
        ans=(ans+M[0].v[0][i]*f[i]%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

 弄了一個矩陣快速冪新板子:

typedef struct Matrix {
    LL m[maxn][maxn];
    LL r;
    LL c;
    Matrix(){
        r = c = 0;
        memset(m, 0, sizeof(m));
    } 
} Matrix;
 
Matrix mul(Matrix m1, Matrix m2, LL mod) {
    Matrix ans = Matrix();
    ans.r = m1.r; ans.c = m2.c;
    for(LL i = 1; i <= m1.r; i++) {
        for(LL j = 1; j <= m2.r; j++) {
            for(LL k = 1; k <= m2.c; k++) {
                if(m2.m[j][k] == 0) continue;
                ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod;
            }
        }
    }
    return ans;
}
Matrix quickmul(Matrix m, LL n, LL mod) {
    Matrix ans = Matrix();
    for(LL i = 1; i <= m.r; i++) {
        ans.m[i][i]  = 1;
    }
    ans.r = m.r;
    ans.c = m.c;
    while(n) {
        if(n & 1) ans = mul(m, ans, mod);
        m = mul(m, m, mod);
        n >>= 1;
    }
    return ans;
}

 滾動數組版:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
 
const LL mod = 1E9+7;
const LL maxn = 110;
LL n, k;
LL f[maxn], a[maxn];
 
struct Matrix {
    LL m[maxn][maxn];
    LL r;
    LL c;
    Matrix(){
        r = c = 0;
        memset(m, 0, sizeof(m));
    }
} M[2];
 
Matrix mul(Matrix m1, Matrix m2, LL mod) {
    Matrix ans = Matrix();
    ans.r = m1.r; ans.c = m2.c;
    for(LL i = 1; i <= m1.r; i++) {
        for(LL j = 1; j <= m2.r; j++) {
            for(LL k = 1; k <= m2.c; k++) {
                if(m2.m[j][k] == 0) continue;
                ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod;
            }
        }
    }
    return ans;
}
void quickmul(LL n, LL mod) {
    for(LL i = 1; i <= M[1].r; i++) {
        M[0].m[i][i]  = 1;
    }
    M[0].r = M[1].r;
    M[0].c = M[1].c;
    while(n) {
        if(n & 1) M[0] = mul(M[1], M[0], mod);
        M[1] = mul(M[1], M[1], mod);
        n >>= 1;
    }
}
 
int main()
{
    int n;
    LL k;
    scanf("%d%lld",&n,&k);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&f[n-i+1]);
    }
    M[1].c = M[1].r = n;
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&M[1].m[1][i]);
    }
    for(int i=2; i<=n; i++)
    {
        M[1].m[i][i-1] = 1;
    }
    k = k-n;
    quickmul(k,mod);
    LL ans = 0;
    for(int i=1; i<=n; i++)
    {
        ans=(ans+M[0].m[1][i]*f[i]%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

 終極指針版(目前最快的):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const LL mod = 1000000007;
const int N = 102;
LL f[N];
struct Matrix
{
    LL v[N][N];
    Matrix(){memset(v,0,sizeof(v));}
} M;
Matrix* mult(Matrix *a,Matrix *b,int n)
{
    Matrix * temp=(Matrix *)malloc(sizeof(M));
    temp->v[0][0] = 0;
    // memset(temp->v,0,sizeof(temp->v));
    for(int i=0; i<n; i++)
    {

        for(int k=0; k<n; k++)
        {
            if(a->v[i][k] == 0 ) continue;
            for(int j=0; j<n; j++)
            {
                temp->v[i][j] = (temp->v[i][j]+(a->v[i][k]*b->v[k][j])%mod)%mod;
            }
        }
    }
    return temp;
}
void pow_mod(Matrix *a,LL t,LL n)
{

    Matrix * ans=(Matrix *)malloc(sizeof(M));
    for(int i=0; i<n; i++)
    {
        ans->v[i][i] = 1;
    }
    while(t)
    {
        if(t&1) ans = mult(a,ans,n);
        a = mult(a,a,n);
        t>>=1;
    }
    LL res = 0;
    for(int i=0; i<n; i++)
    {
        res=(res+ans->v[0][i]*f[i]%mod)%mod;
    }
    printf("%lld\n",res);
}
int main()
{
    int n;
    LL k;
    scanf("%d%lld",&n,&k);
    for(int i=0; i<n; i++)
    {
        scanf("%lld",&f[n-1-i]);
    }
    for(int i=0; i<n; i++)
    {
        scanf("%lld",&M.v[0][i]);
    }
    for(int i=1; i<n; i++)
    {
        M.v[i][i-1] = 1;
    }
    k = k-n;
    pow_mod(&M,k,n);
    return 0;
}
相關文章
相關標籤/搜索