矩阵快速幂。题意:在一个有n个整数元素的集合S中,你可以做操作:选择集合S的两个元素a和b,把a+b放进集合S中。这种操作只能够做k次,要求做完后集合S里所有元素的和最大。输出S里所有元素的和模10000007的结果。
我的解题思路:首先肯定是选择S里面最大的两个元素合并再添加到S集合中,假设一开始S的最大两个元素是a和b。那么第一次添加到S集合的元素是a+b,第二次是a+2b,第三次是2a+3b,第四次是3a+5b。如果用f(n)来表示斐波那契数列第n项的值的话,那么第n次操作添加的元素是f(n)a+f(n+1)b。根据斐波那契数列前n项和等于第n+2项-1的结果可以用矩阵快速幂求出求出一共添加了多少个a和b。最后就可以求和了。
我的解题代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <climits>
#include <algorithm>
using namespace std;
typedef long long Long;
const Long MOD = 10000007;
const Long N = 2;
struct matrix
{
Long n, m;
Long mat[N][N];
matrix(): n(0), m(0) {}
matrix(Long nn, Long mm): n(nn), m(mm) {}
void Unit(Long unit)
{
n = m = unit;
for (Long i=0; i<n; ++i)
for (Long j=0; j<m; ++j)
mat[i][j] = i == j ? 1 : 0;
}
};
pair<Long, Long> maxnum;
matrix init(1, 2), coef(2, 2);
Long n, k;
Long ans;
void InitRead();
void DataProcess();
matrix MatrixMul(matrix a, matrix b, Long mod);
matrix FastPow(matrix base, Long n, Long mod);
int main()
{
while (~scanf("%lld %lld", &n, &k))
{
InitRead();
DataProcess();
}
return 0;
}
void InitRead()
{
maxnum.first = maxnum.second = ans = 0;
coef.mat[0][0] = 0;
coef.mat[0][1] = coef.mat[1][0] = coef.mat[1][1] = 1;
init.mat[0][0] = init.mat[0][1] = 1;
Long tmp;
while (n--)
{
scanf("%lld", &tmp);
ans += tmp;
if (tmp > maxnum.second)
{
maxnum.second = tmp;
if (maxnum.first < maxnum.second) swap(maxnum.first, maxnum.second);
}
}
ans -= maxnum.first;
ans %= MOD;
return;
}
void DataProcess()
{
matrix res = MatrixMul(init, FastPow(coef, k+1, MOD), MOD);
ans += (res.mat[0][0] - 1) * maxnum.second % MOD;
ans %= MOD;
ans += (res.mat[0][1] - 1) * maxnum.first % MOD;
ans %= MOD;
printf("%lld\n", ans);
return;
}
matrix MatrixMul(matrix a, matrix b, Long mod)
{
matrix res(a.n, b.m);
for (int i=0; i<res.n; ++i)
{
for (int j=0; j<res.m; ++j)
{
res.mat[i][j] = 0;
for (int l=0; l<a.m; ++l)
{
res.mat[i][j] += a.mat[i][l] * b.mat[l][j];
}
res.mat[i][j] %= mod;
}
}
return res;
}
matrix FastPow(matrix base, Long n, Long mod)
{
matrix res;
res.Unit(base.n);
while (n)
{
if (n & 1) res = MatrixMul(res, base, mod);
base = MatrixMul(base, base, mod);
n >>= 1;
}
return res;
}