版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/83028800
Description
有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大
值。(数据保证这个值为非负数)
对于100%的数据,有 n<=105,k<=109,|ai|<=105
输出一个整数,表示和的最大值。答案对10000007取模。
Solution
一开始没看到k的范围。。。sb了
然后看到答案保证非负以为只有正正和正负的情况。。。又sb了
这个a的绝对值引人深撕。显然每次贪心地取两个最大值一定是最优秀的。
考虑初始两个最大值都是正整数的情况,感受一下可以发现贡献就是斐波那契数列求和
考虑初始两个最大值一正一负的情况,我们可以暴力把负数加成非负数,然后同上
考虑初始两个最大值都是负数,显然就是这两个数取k次
斐波那契数列求和的话s[n]=f[n+2]-1,矩阵上即可
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const int MOD=10000007;
const int N=200005;
int a[N];
struct Mat {
LL r[3][3];
Mat() {fill(r,0);}
Mat operator *(Mat B) const {
Mat A=*this,C;
rep(i,1,2) rep(j,1,2) {
rep(k,1,2) C.r[i][j]=(C.r[i][j]+A.r[i][k]*B.r[k][j]%MOD)%MOD;
}
return C;
}
Mat operator ^(int x) const {
Mat A=*this,C=A; x--;
for (;x;x>>=1) {
if (x&1) C=C*A;
A=A*A;
}
return C;
}
} A;
bool cmp(int x,int y) {
return x>y;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n,k,ans=0; scanf("%d%d",&n,&k);
rep(i,1,n) {
scanf("%d",&a[i]);
ans=(ans+a[i])%MOD;
}
std:: sort(a+1,a+n+1,cmp);
if (a[1]<0&&a[2]<0) {
ans=(ans+(a[1]+a[2])*k%MOD)%MOD;
ans=(ans%MOD+MOD)%MOD;
printf("%d\n", ans);
return 0;
}
if (a[1]>0&&a[2]<0) {
while (k) {
k--;
a[++n]=a[2];
a[2]+=a[1]; ans=(ans+a[2])%MOD;
if (a[2]>=0) break;
}
std:: sort(a+1,a+n+1,cmp);
}
A.r[2][1]=A.r[1][2]=A.r[2][2]=1;
A=A^(k+2);
ans=(ans+(A.r[2][1]-1)*a[2]%MOD+(A.r[2][2]-2)*a[1]%MOD)%MOD;
ans=(ans%MOD+MOD)%MOD;
printf("%d\n", ans);
return 0;
}