题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5171
题意:给定一个数列,要求不断的取最大和次大的两个数字的和加入原数列,重复该操作k次,问最终数列的和是多少
思路:由于k很大,如果直接不停地累加、更新,会超时,这样就用到了快速幂,每次的和sum更新为sum+最大+次大,最大的数更新为原来最大+原来次大,次大的数更新为原来的最大,所以用一个3*3的矩阵表示这个三个数字({1,1,1},{0,1,1},{0,1,0})累乘k次,最后分别乘原来的sum,最大,次大,代码如下
代码:
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 100005;
#define mod 10000007
struct matrix
{
ll m[3][3];
};
matrix mul(matrix x, matrix y)
{
matrix temp;
memset(temp.m, 0, sizeof(temp.m));
int i, j, k;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (x.m[i][j] == 0)
{
continue;
}
for (k = 0; k < 3; k++)
{
if (y.m[j][k] == 0)
{
continue;
}
temp.m[i][k] = (temp.m[i][k] + (x.m[i][j] * y.m[j][k]) % mod) % mod;
}
}
}
return temp;
}
matrix quickpow(matrix a, int n)
{
matrix res;
memset(res.m, 0, sizeof(res.m));
for (int i = 0; i < 3; i++)
{
res.m[i][i] = 1;
}
while (n)
{
if (n & 1)
{
res = mul(res,a);
}
n >>= 1;
a = mul(a, a);
}
return res;
}
int main()
{
int n,k;
int a[maxn];
while(scanf("%d%d",&n,&k)!=EOF)
{
ll sum=0;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n);
//cout<<m1<<" "<<m2<<endl;
matrix y,aa,x;
aa.m[0][0]=1;
aa.m[0][1]=1;
aa.m[0][2]=1;
aa.m[1][0]=0;
aa.m[1][1]=1;
aa.m[1][2]=1;
aa.m[2][0]=0;
aa.m[2][1]=1;
aa.m[2][2]=0;
y = quickpow(aa,k);
printf("%lld\n", (y.m[0][0] * sum + y.m[0][1] *a[n-1] + y.m[0][2] * a[n-2]) % mod);
}
return 0;
}