题意:GTY的朋友ZZF的生日要来了,GTY问他的基友送什么礼物比较好,他的一个基友说送一个可重集吧!于是GTY找到了一个可重集S,GTY能使用神犇魔法k次,每次可以向可重集中加入一个数 a+b(a,b∈S),现在GTY想最大化可重集的和,这个工作就交给你了。 注:可重集是指可以包含多个相同元素的集合
分析:想要和最大,那么每次必定从集合里面拿出最大的两个出来相加,然后k次后面就类似斐波那契数列了。
由斐波那契数列公式知:Fn=Fn-1+Fn-2,求和公式有Sn=Sn-1+Fn.因此用这两个公式构造矩阵,进行矩阵快速幂。
Sn-1 | 1 1 0| Sn
Fn * | 0 1 1| =Fn+1
Fn-1 | 0 1 0| Fn
然后ans=(Sn+(sum-a[n-1]-a[n-2]))%mod(sum为原集合总和,然后减去最大的两个,加上k次后的序列之和(即斐波那契数列和))。
#include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 10000007 #define inf 0x3f3f3f3f #define N 40010 #define clr(a) (memset(a,0,sizeof(a))) using namespace std; struct matrix { LL m[3][3]; }; LL a[100010]; matrix mult(matrix a,matrix b) { matrix c; memset(c.m,0,sizeof(c.m)); for(int i=0;i<3;i++) for(int j=0;j<3;j++) { if(a.m[i][j]==0)continue; for(int k=0;k<3;k++) { if(b.m[j][k]==0)continue; c.m[i][k]+=a.m[i][j]*b.m[j][k]%mod; c.m[i][k]%=mod; } } return c; } matrix quickmod(matrix a,int n) { matrix temp; memset(temp.m,0,sizeof(temp.m)); for(int i=0;i<=2;i++)temp.m[i][i]=1; while(n) { if(n&1)temp=mult(temp,a); a=mult(a,a); n/=2; } return temp; } int main() { LL n,k; while(scanf("%I64d%I64d",&n,&k)>0) { LL sum=0; for(int i=0;i<n;i++)scanf("%I64d",&a[i]),sum+=a[i]; sort(a,a+n); matrix ans; ans.m[0][0]=1;ans.m[0][1]=1;ans.m[0][2]=0; ans.m[1][0]=0;ans.m[1][1]=1;ans.m[1][2]=1; ans.m[2][0]=0;ans.m[2][1]=1;ans.m[2][2]=0; ans=quickmod(ans,k+1); printf("%I64d ",(1LL*ans.m[0][0]*a[n-2]+1LL*ans.m[0][1]*a[n-1]+1LL*ans.m[0][2]*a[n-2]+sum-(a[n-1]+a[n-2]))%mod); } }