description
有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值。(数据保证这个值为非负数)
analysis
-
正解矩乘
-
考虑aaa为最大值、bbb为次大值,那么每次加入的数分别为a+b,2a+b,3a+2b,5a+3b...a+b,2a+b,3a+2b,5a+3b...a+b,2a+b,3a+2b,5a+3b...
-
所以a,ba,ba,b的系数分别就是斐波那契数列,稍微有点不同而已
-
又知道∑i=1na[i]=a[i+2]−1(a[1]=a[2]=1)\sum_{i=1}^na[i]=a[i+2]-1(a[1]=a[2]=1)∑i=1na[i]=a[i+2]−1(a[1]=a[2]=1),所以a,ba,ba,b的系数总和可以直接用矩乘求出来
-
注意次大值可能是负数,就需要不断加上最大值,变成正数后再用上面的方法求解
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define reg register ll
#define mod 10000007ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll a[MAXN];
ll n,k,sum;
struct matrix
{
ll m[2][2];
}c;
matrix A={1,1,1,0};
matrix I={1,0,0,1};
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline bool cmp(ll a,ll b)
{
return a>b;
}
O3 inline matrix operator*(matrix a,matrix b)
{
memset(c.m,0,sizeof(c.m));
fo(i,0,1)fo(j,0,1)fo(k,0,1)
(c.m[i][j]+=a.m[i][k]*b.m[k][j]%mod)%=mod;
return c;
}
O3 inline matrix pow(matrix x,ll y)
{
matrix z=I;
while (y){if (y&1)z=z*x;x=x*x,y/=2;}
return z;
}
O3 int main()
{
n=read(),k=read();
fo(i,1,n)a[i]=read(),(sum+=a[i])%=mod;
sort(a+1,a+n+1,cmp);
while (a[1]>0 && a[2]<0)
{
sum+=a[1]+a[2];
a[2]=a[1]+a[2];
k--;
}
printf("%lld\n",(sum+a[1]*(pow(A,k+2).m[0][0]-2)+a[2]*(pow(A,k+1).m[0][0]-1)+mod)%mod);
return 0;
}

该博客介绍了如何利用矩阵乘法解决一个关于可重集合的操作问题,其中每次操作可以加入a+b(a和b已存在于集合中)。通过分析a和b的系数与斐波那契数列的关系,博主提出了一个正解矩乘的方法来求解最大可能的集合和。在某些情况下,由于次大值可能为负,需要转换为正数再进行计算。
1524

被折叠的 条评论
为什么被折叠?



