GTY's birthday gift
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1176 Accepted Submission(s): 449
3 2 3 6 2
35
这真是一个神奇的题,更神奇的是矩阵和数论给我带来的惊喜。矩阵能够求斐波那契数,不仅仅是斐波那契数神奇,矩阵也是如此的神奇。
我们从题目中能够推测:
假设a是序列中最大数,b是次大数,那么每一次多出来的是:a+b,2a+b,3a+2b,5a+3b..................
比原序列多出来的值是:a+b,3a+2b,6a+4b....................
其中我们能发现a前系数为1 2 3 5 8...............
b前系数为:1 1 2 3 5 8......................
很明显的斐波那契数列。如果接触过POJ3070的小伙伴可能马上就有思路了。矩阵快速幂求斐波那契数:
这里初始化矩阵为2阶:
1 1
1 0
自乘:
2 1
1 1
再自乘:
3 2
2 1
再自乘:
5 3
3 2
我们发现第一层上边的两个数一直都是斐波那契数。
这个时候我们根据矩阵乘法的特性,加上各种推论能够构造一个矩阵:
1 1 1
0 1 1
0 1 0
自乘之后
1 3 2
0 2 1
0 1 1
无限幂次都能保证第一行的三个元素分别代表: 1(第一个数永远都是1),比原序列多出的a的个数,比原序列多出的b的个数。
然后我们就能写出对应的代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long int
int const MOD = 10000007;
struct matrix
{
ll m[3][3];
};
int a[100010];
matrix multiply(matrix x, matrix y) //矩阵乘法
{
matrix tmp;
memset(tmp.m, 0, sizeof(tmp.m));
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
if(x.m[i][j] == 0)
continue;
for(int k = 0; k < 3; k++)
{
if(y.m[j][k] == 0)
continue;
tmp.m[i][k] += x.m[i][j] * y.m[j][k] % MOD;
tmp.m[i][k] %= MOD;
}
}
}
return tmp;
}
matrix quickmod(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 = multiply(res, a);
n >>= 1;
a = multiply(a, a);
}
return res;
}
int main()
{
int n,k;
while(~scanf("%d%d",&n,&k))
{
ll sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n);
matrix tmp;
tmp.m[0][0] = 1; tmp.m[0][1] = 1; tmp.m[0][2] = 1;
tmp.m[1][0] = 0; tmp.m[1][1] = 1; tmp.m[1][2] = 1;
tmp.m[2][0] = 0; tmp.m[2][1] = 1; tmp.m[2][2] = 0;
tmp = quickmod(tmp, k);
printf("%lld %lld %lld\n",tmp.m[0][0],tmp.m[0][1],tmp.m[0][2]);
ll output= (tmp.m[0][0] * sum + tmp.m[0][1] * a[n - 1] + tmp.m[0][2] * a[n - 2]) % MOD;
printf("%lld\n",output);
}
}