bzoj4547 Hdu5171 小奇的集合 矩陣乘法
阿新 • • 發佈:2018-12-14
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;
}