题意:
本来多重集里有n个数,每次都从一列数中取最大的两个数求和加入多重集,进行k次操
作后,求多重集中所有元素的和%10000007(2≤n≤100000,1≤k≤1000000000)
分析:
类Fib数列,虽然中间结果会超longlong,但是%10000007的话可以保证在整数范围内。
但是,O(k)的时间复杂度必须用矩阵快速幂优化到O(logk)。
显然每次会从可重集中选择最大的两个进行操作,设这两数为a,b(a>=b),操作之后的数一定是操作后集合中最大的,下一次选取的数一定是a+b和a,这就形成了一个类似于斐波那契数列的东西,矩阵乘法快速幂求前n项和即可,转移矩阵如下![]()
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int mod = 10000007;
const int maxm = 5;
int a[100010];
struct Matrix{
ll mat[maxm][maxm];
Matrix(){memset(mat,0,sizeof(mat));}
Matrix operator *(Matrix A){
Matrix ret;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
ret.mat[i][j] = (ret.mat[i][j]+(mat[i][k]*A.mat[k][j])%mod)%mod;
}
}
}
return ret;
}
};
Matrix pow_mul(Matrix A,int n){
Matrix res;
for(int i=0;i<maxm;i++) res.mat[i][i] = 1;
while(n){
if(n&1) res = res*A;
A = A*A;
n>>=1;
}
return res;
}
int main()
{
int n,k;
ll sum;
while(~scanf("%d%d",&n,&k)){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
sum = 0LL;
for(int i=1;i<n-1;i++)
sum += a[i];
Matrix A,B;
A.mat[0][0] = A.mat[0][1] = A.mat[0][2] = 1;
A.mat[1][1] = A.mat[1][2] = 1;
A.mat[2][1] = 1;
A = pow_mul(A,k);
B.mat[0][0] = a[n-1]+a[n];
B.mat[1][0] = a[n];
B.mat[2][0] = a[n-1];
A = A*B;
sum = (sum+A.mat[0][0])%mod;
printf("%I64d\n",sum);
}
return 0;
}