题意:给定一个数列含有n个数,执行k次操作(n,k<109),每次操作从中取出2个数,求和加起来在放回原数列(下一次操作对新数列进行操作) 求 最后数列可能的最大总和
分析:首先首次次操作应该选取当前数列中最大的2个数a和b (a>b) 而第二次应该选取a+b
和a 第三次 为a+b+a和a+b 这样每次新构成的数,是上一次选取的2个数之和,a和b的系数 相当于斐波那契数列。
对于快速求斐波那契数列可以构造矩阵
1 1
1 0
而这题加上对斐波那契数列的求和,所以可以构造
1 1 0
1 0 0
1 1 1
这样的矩阵 来附加求和功能
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include<stack>
#define inf 0x3f3f3f3f
#define ll long long
#define bug puts("bugbugbug");
using namespace std;
const int maxn = 20;
const int maxm = 20;
ll mod=10000007;
int a[100005];
struct Matrix {
int n, m;
ll a[maxn][maxm];
void clear() {
n = m = 0;
memset(a, 0, sizeof(a));
}
Matrix operator * (const Matrix &b) const { //实现矩阵乘法
Matrix tmp;
tmp.n = n;
tmp.m = b.m;
for (int i = 0; i < n; i++)
for (int j = 0; j < b.m; j++) tmp.a[i][j] = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (!a[i][j]) continue;
for (int k = 0; k < b.m; k++)
tmp.a[i][k] += a[i][j] * b.a[j][k], tmp.a[i][k] %= mod;
}
return tmp;
}
void Copy(const Matrix &b) {
n = b.n, m = b.m;
for (int i = 0; i < n; i++)
for(int j = 0; j < m; j++) a[i][j] = b.a[i][j];
}
void unit(int sz) {
n = m = sz;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) a[i][j] = 0;
a[i][i] = 1;
}
}
};
Matrix A, B,C;
Matrix Matrix_pow(Matrix A, ll k, ll mod) { //矩阵快速幂
Matrix res;
res.clear();
res.n = res.m = A.n;
for (int i = 0; i < A.n; i++) res.a[i][i] = 1;
while(k) {
if (k & 1) res.Copy(A * res);
k >>= 1;
A.Copy(A * A);
}
return res;
}
int main()
{
int n,k;
A.clear();
A.n=A.m=3;
A.a[0][0]=1;A.a[0][1]=1;A.a[0][2]=0;
A.a[1][0]=1;A.a[1][1]=0;A.a[1][2]=0;
A.a[2][0]=1;A.a[2][1]=1;A.a[2][2]=1;
while(~scanf("%d%d",&n,&k))
{
int ans=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
ans=(ans+a[i])%mod;
}
B.clear();
B.Copy(Matrix_pow(A,k,mod));
C.n=3;C.m=1;
sort(a,a+n);
C.a[0][0]=a[n-1];
C.a[1][0]=a[n-2];
C.a[2][0]=0;
C.Copy(B*C);
printf("%d\n",(ans+C.a[2][0])%mod);
}
}