hdu 5171 GTY's birthday gift
GTY's birthday gift
问题描述
GTY的朋友ZZF的生日要来了,GTY问他的基友送什么礼物比较好,他的一个基友说送一个可重集吧!于是GTY找到了一个可重集S,GTY能使用神犇魔法k次,每次可以向可重集中加入一个数 a+b (a,b\in S)a+b(a,b∈S),现在GTY想最大化可重集的和,这个工作就交给你了。
注:可重集是指可以包含多个相同元素的集合
输入描述
多组数据(约3组),每组数据的第一行有两个数n,k(2 \leq n \leq 100000,1 \leq k \leq 1000000000)n,k(2≤n≤100000,1≤k≤1000000000) 表示初始元素数量和可使用的魔法数,第二行包含n个数a(1 \leq a_i \leq 100000)a(1≤ai≤100000)表示初始时可重集的元素
输出描述
对于每组数据,模10000007输出可重集可能的最大和。
输入样例
3 2 3 6 2
输出样例
35
这道题的解题思路很简单,用矩阵快速幂实现一个斐波那契数列求和(初值改变)
难点在于矩阵的构造,首先列出三个要维护的值
| sum |
| a[n-1] |
| a[n-2] |
那么可以想到这个矩阵的下一个形式必然为
| sum+a[n-1]+a[n-2] |
| a[n-1]+a[n-2] |
| a[n-1] |
由此可以得到需要构造的友矩阵为
| 1 1 1 |
| 0 1 1 |
| 0 1 0 |
有了这个友矩阵,就可以进行矩阵快速幂了,先求
| 1 1 1 |
| 0 1 1 | 的K次方,然后再乘以初始矩阵就可以得到sum
| 0 1 0 |
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; const int maxn=111; const int Max=1e5+10; const int MOD=10000007; int a[Max]; struct matrix { int w; LL m[maxn][maxn]; //注意矩阵也要用LL,不然会出现溢出 matrix(int ww):w(ww){memset(m,0,sizeof(m));}; matrix(){} }; matrix operator * (matrix a,matrix b) { matrix res(3); LL x; for(int i=0;i<res.w;i++) { for(int j=0;j<res.w;j++) { x=0; for(int k=0;k<res.w;k++) { x=(x+(LL)a.m[i][k]*b.m[k][j])%MOD; } res.m[i][j]=x; } } return res; } matrix fast_cover(int k) { matrix base(3); base.m[0][0]=base.m[0][1]=base.m[0][2]=1; base.m[1][1]=base.m[1][2]=base.m[2][1]=1; base.m[1][0]=base.m[2][0]=base.m[2][2]=0; matrix s(3); s.m[0][0]=s.m[1][1]=s.m[2][2]=1; while(k) { if(k&1) s=s*base; base=base*base; k>>=1; } return s; } int main() { int n,k;LL sum; while(scanf("%d%d",&n,&k)!=EOF) { sum=0; for(int i=0;i<n;i++) scanf("%d",&a[i]),sum+=a[i]; sort(a,a+n); matrix ss=fast_cover(k); LL ans=(ss.m[0][0]*sum+ss.m[0][1]*a[n-1]+ss.m[0][2]*a[n-2])%MOD; printf("%I64d\n",ans); } return 0; }