【传送门:BZOJ4547】
简要题意:
给有一个大小为n的可重集S,每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值。(数据保证这个值为非负数)
题解:
我们先来看看,因为我们要得到最大的S,所以每次我们都要使得a+b最大
首先排除一开始得到的a,b为负数的情况,我们将a+b放进S里,那么下一次操作就会将a+(a+b)(假设a>b)放进S里,再下一次就会将(a+b)+(a+b+a)放进S里,这样子就相当于一个斐波那契数列,我们就可以用矩阵乘法来求值
但是数据保证和的最大值为非负数,就说明a一定为正数,有可能b为负数
那么我们就暴力操作直到将b变为非负数即可
WA了半版,发现原来不能用负数来取mod,要+mod数再取mod,气死我了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; int Mod=10000007; struct node { LL a[4][4]; node() { memset(a,0,sizeof(a)); } }d,cmd; node chengfa(node a,node b) { node c; for(int i=1;i<=3;i++) { for(int j=1;j<=3;j++) { for(int k=1;k<=3;k++) { c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%Mod; } } } return c; } node p_mod(node a,int b) { node ans; ans.a[1][1]=1;ans.a[2][2]=1;ans.a[3][3]=1; while(b!=0) { if(b%2==1) ans=chengfa(ans,a); a=chengfa(a,a); b/=2; } return ans; } LL a[110000]; int main() { LL n,k; scanf("%lld%lld",&n,&k); LL sum=0; LL max1=-1<<31,max2=-1<<31; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); sum=(sum+a[i]+Mod)%Mod; if(a[i]>max1) { max2=max1; max1=a[i]; } else if(a[i]>max2) max2=a[i]; } if(k==0){printf("%lld ",sum);return 0;} while(max2<0) { max2=max2+max1; sum=(sum+max2)%Mod; k--;if(k==0){printf("%lld ",sum);return 0;} } d.a[1][1]=max1;d.a[1][2]=max2;d.a[1][3]=sum; cmd.a[1][1]=1;cmd.a[2][1]=1; cmd.a[1][2]=1; cmd.a[1][3]=1;cmd.a[2][3]=1;cmd.a[3][3]=1; d=chengfa(d,p_mod(cmd,k)); printf("%lld ",d.a[1][3]); return 0; }