Time:2016.08.18
Author:xiaoyimi
转载注明出处谢谢
传送门1
传送门2
思路:
基本想法是每次找出最大的两个相加即可
而且由于题目要求,起始的n个数中至少有一个是正整数
当最大的两个数都是非负整数时,我们发现每次的求值就是一个这样的数列
fi=fi−1+fi−2
是不是很眼熟,很像fibonacci数列……
那我们直接构造转移矩阵,然后矩阵快速幂就可以了啊……
那求和怎么办?
我们先从
S1
入手
S1=f1=f3−f2
那
S2
,
S3
呢?
S2=f1+f2=(f3+f2)−f2=f4−f2
S3=f1+f2+f3=(f4+f3)−f2=f5−f2
是不是有些奥妙重重?
那我们就得到结论
Sn=fn+2−f2=2fn+fn−1−f2
这样求和问题就解决了
那如果上来一个负数一个正数怎么办
观察ai的取值范围[-10^5,10^5]
那么这一正一负的最坏情况就是1和-10^5
只要累加10^5次就可以把集合中最大的两个数变成正数了
所以小范围暴力递推就可以了
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define mo 10000007
#define LL long long
using namespace std;
int n,k;LL tot;
int a[100005];
struct matrix
{
LL m[3][3];
void clear(){memset(m,0,sizeof(m));}
};
matrix mul(matrix a,matrix b)
{
matrix c;
c.clear();
for (int i=1;i<=2;i++)
for (int j=1;j<=2;j++)
for (int k=1;k<=2;k++)
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]%mo)%mo;
return c;
}
void work(int aa,int bb,int k)
{
matrix ans,x;
ans.clear();x.clear();
ans.m[1][1]=aa;
ans.m[1][2]=bb;
x.m[1][1]=x.m[1][2]=x.m[2][1]=1;
for (;k;k>>=1,x=mul(x,x))
if (k&1) ans=mul(ans,x);
tot=((LL)tot+ans.m[1][1]*2+ans.m[1][2]-aa)%mo;
tot=(tot+mo)%mo;
cout<<tot;
}
main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+n+1);
for (int i=1;i<=n-2;i++)
tot=(tot+a[i])%mo;
int x=a[n],y=a[n-1];
for (int i=1;i<=k;i++)
if(y>=0) {work(x,y,k-i+1);return 0;}
else tot=(tot+y)%mo,y=x+y;
}