【JZOJ5228】【BZOJ4547】小奇的集合

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

description

有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值。(数据保证这个值为非负数)


analysis

  • 正解矩乘

  • 考虑 a a a为最大值、 b b b为次大值,那么每次加入的数分别为 a + b , 2 a + b , 3 a + 2 b , 5 a + 3 b . . . a+b,2a+b,3a+2b,5a+3b... a+b,2a+b,3a+2b,5a+3b...

  • 所以 a , b a,b a,b的系数分别就是斐波那契数列,稍微有点不同而已

  • 又知道 ∑ i = 1 n a [ 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 , b a,b a,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值