题目描述:http://acm.hdu.edu.cn/showproblem.php?pid=5171
算法:
可以先将数组a[]排序,然后序列 a1 , a2 , … , an 即为有序序列,则第一次加入的就是 an + an-1 ,第二次就是 an + (an + an-1) ,如此循环就构成了斐波那契序列。
设斐波那契序列的第k项为Fk,则可知第k次加入的即为 Fk+1 * an + Fk * an-1
设斐波那契序列的前k项和为Sk, 则所得结果res即为:a1 + a2 + … + an-1 + an + (Sk+1 - 1) * an + Sk * an-1
实现方法:
由于需要对结果取余,所以可以考虑用矩阵快速幂来实现斐波那契序列,具体怎么实现可以看这里。
并且根据公式可以知道 Sk = 2 * Fk + Fk-1 - 1 , 代入上式即可。
#include <iostream> #include <cstdio> #include <vector> #include <cmath> #include <string> #include <string.h> #include <algorithm> using namespace std; #define LL __int64 #define eps 1e-8 const int MOD = 10000007; const int maxn = 100000 + 5; const int N = 2; struct Mat { LL mat[N][N]; } a; void init() { a.mat[0][0] = a.mat[0][1] = a.mat[1][0] = 1; a.mat[1][1] = 0; } Mat operator *(Mat a , Mat b) { Mat tmp; memset(tmp.mat , 0 , sizeof(tmp.mat)); for(int i = 0 ; i < N ; i++) for(int j = 0 ; j < N ; j++) for(int k = 0 ; k < N ; k++) tmp.mat[i][j] = (tmp.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % MOD; return tmp; } Mat operator ^(Mat a , int k) { Mat tmp; for(int i = 0 ; i < N ; i++) for(int j = 0 ; j < N ; j++) tmp.mat[i][j] = (i == j); while(k) { if(k & 1) tmp = tmp * a; a = a * a; k /= 2; } return tmp; } LL Fab(int k) { Mat tmp; tmp = a ^ k; return tmp.mat[1][0]; } LL a_[maxn]; int main() { init(); LL n , k , i , j , res; while(~scanf("%lld %lld" , &n , &k)) { for(i = 1 , res = 0 ; i <= n ; i++) { scanf("%lld" , &a_[i]); res += a_[i]; } sort(a_ + 1 , a_ + n + 1); LL tmp = ((2 * Fab(k + 1) + Fab(k) + 10000005) * a_[n] + (2 * Fab(k) + Fab(k - 1) + 10000006) * a_[n - 1]) % MOD; res = (res + tmp) % MOD; printf("%lld\n" , res); } return 0; }
另外记录一个斐波那契的通项公式:
时间: 2024-08-01 11:10:57