生成序列 1,3,8,22,60,164 .如何使我的代码更有效率
Generating a sequence 1,3,8,22,60,164 .How to make my code more effficient?
#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) ;
} ;
相关文章:
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 如何使我的 sizeof sum 结构与空参数包一起工作
- 我应该使我的局部变量常量还是可移动的
- 矢量迭代器在尝试调用函数时使我的程序崩溃
- 使用唯一指针调用函数会使我的程序崩溃
- C++ 如何使我的程序不会删除正在使用的文件?
- C++单例模板类使我的程序崩溃
- 如何使我的 cmake 项目所需的某些 c++ 功能
- 我怎样才能阻止我的程序输出时间,它使我的程序难以阅读
- 如何使我的链表在C++中向后打印
- 我将如何获得正确的公式结构以使我的程序C++中的侧 c?
- 如果输入变量的数据类型与以前不同,如何使我的循环仍然正常运行?
- 当自动编译对象文件时,如何使我的makefile使用我的cflags标志
- LOCAL_SHARED_LIBRARIES使我的应用程序崩溃
- 为什么使用 nullPtr 调用函数不会使我的应用程序崩溃
- 如何使我的单词查找更清晰、更高效
- 无法使我的第一个Windows OpenGL窗口抬起并运行
- 我可以以某种方式使我的矢量/数组动态更改装置数量吗?
- 难以使我的插入操作员过头
- 为什么叮当使我的简单阶乘函数过于复杂