生成序列 1,3,8,22,60,164 .如何使我的代码更有效率

Generating a sequence 1,3,8,22,60,164 .How to make my code more effficient?

本文关键字:何使 我的 有效率 代码      更新时间:2023-10-16
#include <vector>
#include<iostream>
#include<stdio.h>
#define REP(i,n) for (ll i = 1; i <= n; i++)
using namespace std;
typedef unsigned long long int ll;
typedef vector<vector<ll> > matrix;
ll MOD = 1000000007;
const ll K = 2;
// computes A * B
matrix mul(matrix A, matrix B)
{
    matrix C(K+1, vector<ll>(K+1));
    REP(i, K) REP(j, K) REP(k, K)
        C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD;
    return C;
}
// computes A ^ p
matrix pow(matrix A, ll p)
{
    if (p == 1)
        return A;
    if (p & 1)
        return mul(A, pow(A, p-1));
    matrix X = pow(A, p>>1);
    return mul(X, X);
}
// returns the N-th term of Fibonacci sequence
ll fib(ll N)
{
    // create vector F1
    vector<ll> F1(K+1);
    F1[1] = 1;
    F1[2] = 3;
    // create matrix T
    matrix T(K+1, vector<ll>(K+1));
    T[1][1] = 0, T[1][2] = 1;
    T[2][1] = 2, T[2][2] = 2;
    // raise T to the (N-1)th power
    if (N == 1)
        return 1;
    T = pow(T, N-1);
    // the answer is the first row of T . F1
    ll res = 0;
    REP(i, K)
        res = (res + ((T[1][i] )* (F1[i]))) %MOD;
    return res;
}
ll fib2(ll n)
{
    if(n==1)
    return 1;
    ll a=1;ll b=3;ll c;
    for(ll i=3;i<=n;i++)
    {
        c=(2*a+2*b)%MOD;
        a=b;
        b=c;
    }
    return c;
}
int main()
{
    ll t;
    scanf("%llu",&t);
   // t=10000;
    ll n=1;
    while(t--)
    {
        scanf("%llu",&n);
        //n=1;
       // n++;
     //  n=1000000000;
        printf("%llun",fib(n));
    }
    return 0;
}

我正在编写一个代码来生成 1,3,8,22,60,164 a[n]=2*(a[n-1]+a[n-2]( mod 10^9+7 .我正在使用模幂和矩阵乘法来生成这个序列。对于最坏情况,即 n=10^9,我怎样才能将其时间从 2.3 秒缩短。10000次到0.5到1秒左右?请给我建议以提高此代码的速度。

我怀疑vector是这里的罪魁祸首 - 动态分配和数字的东西不能很好地混合。
2x2 矩阵太小了,任何花哨的算法都不会产生任何影响。我有一种预感,由于头顶的幻想,他们实际上会更糟

您是否尝试过展开循环并放弃动态分配?

我希望这是正确的:

void mul(ll A[][2], ll B[][2], ll C[][2])
{
    C[0][0] = (A[0][0] * B[0][0]) % MOD;
    C[0][0] = (C[0][0] + A[0][1] * B[1][0]) % MOD;
    C[0][1] = (A[0][0] * B[0][1]) % MOD;
    C[0][1] = (C[0][1] + A[0][1] * B[1][1]) % MOD;
    C[1][0] = (A[1][0] * B[0][0]) % MOD;
    C[1][0] = (C[1][0] + A[1][1] * B[1][0]) % MOD;
    C[1][1] = (A[1][0] * B[0][1]) % MOD;
    C[1][1] = (C[1][1] + A[1][1] * B[1][1]) % MOD;
}
void pow(ll A[][2], ll p, ll out[][2])
{
    if (p == 1)
    {
        out[0][0] = A[0][0];
        out[0][1] = A[0][1];
        out[1][0] = A[1][0];
        out[1][1] = A[1][1];
        return;
    }
    if (p & 1)
    {
        ll B[2][2] = {{0}};
        pow(A, p - 1, B);
        mul(A, B, out);
    }
    else
    {
        ll X[2][2] = {{0}};
        pow(A, p >> 1, X);
        mul(X, X, out);
    }
}
ll fibv(ll N)
{
    ll T[2][2] =
    {
        {2, 2},
        {1, 0}
    };
    if (N == 1)
        return 1;
    ll RM[2][2] = {{0}};
    pow(T, N-1, RM);
    ll res = RM[0][1] % MOD;
    res = (res + RM[0][0] * 3) % MOD;
    return res;
}

https://en.wikipedia.org/wiki/Strassen_algorithm

您甚至可以在麻省理工学院开放课件算法入门课程或斯坦福大学算法课程的视频讲座中找到它

如果您专注于 2x2 矩阵,您将获得显着的加速:

struct matrix {
  ll a, b, c, d ;
  void Square() ;
  void Mul (const matrix& M) ;
  } ;