Bzoj P4547 [Hdu5171]小奇的集合___递推+矩阵乘法快速幂

127 篇文章 0 订阅
13 篇文章 0 订阅

题目大意:

有一个可重集 S S S,一开始大小为 n n n,集合中有 n n n个数, a 1 , a 2 , . . . , a n − 1 , a n a_1,a_2,...,a_{n-1},a_n a1,a2,...,an1,an,小奇每次操作可以加入一个数 a + b a+b a+b( a , b ∈ S a,b∈S a,bS),求 k k k次操作后它可获得的 S S S的和的最大值。
保 证 S 为 非 负 数 保证S为非负数 S
n &lt; = 1 0 5 , k &lt; = 1 0 9 , ∣ a i ∣ &lt; = 1 0 5 n&lt;=10^5,k&lt;=10^9,|ai|&lt;=10^5 n<=105k<=109ai<=105

分析:

在这里插入图片描述

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>

#define MT(x) memset(x, 0, sizeof(x))
#define MP(x, y) memcpy(x, y, sizeof(y))

#define modn 10000007
#define N 100005

using namespace std;

typedef long long ll;

ll D[5][5], C[5][5], A[N], F[5], m;
int n;

void Pre_Work()
{
    C[1][1] = 1, C[1][2] = 1, C[1][3] = 0;
	C[2][1] = 1, C[2][2] = 0, C[2][3] = 0;
	C[3][1] = 1, C[3][2] = 1, C[3][3] = 1;	
}

void mul()
{
	ll G[5][5]; MT(G);
    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 3; j++)
            for (int k = 1; k <= 3; k++)
               G[i][j] = (G[i][j] + D[i][k] * C[k][j]) % modn;
    MP(D, G);
}

void mulself()
{
    ll G[5][5]; MT(G);
    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 3; j++)
            for (int k = 1; k <= 3; k++)
                G[i][j] = (G[i][j] + C[i][k] * C[k][j]) % modn;
    MP(C, G);
}

int main()
{
	Pre_Work();
	scanf("%d %lld", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%lld", &A[i]), F[3] = (F[3] + A[i]) % modn;
	sort(A + 1, A + n + 1);
	F[1] = A[n];
	F[2] = A[n - 1];
	if (F[1] < 0 && F[2] < 0)
	{
	    F[3] = (F[3] + (F[1] + F[2]) * m % modn) % modn; 
	    printf("%lld\n", (F[3] + modn) % modn);
	    return 0;
	}
	
	while (F[2] < 0 && m > 0)
	{
		F[2] = (F[2] + F[1]) % modn;
		F[3] = (F[3] + F[2]) % modn;
		--m;
	}
	if (!m) printf("%lld\n", (F[3] + modn) % modn); 
	else 
	{
		MP(D, C); --m;
		for (; m; m >>= 1)
		{
			if (m & 1) mul();
			mulself(); 
		}
		ll G[5]; MT(G);
		for (int i = 1; i <= 3; i++)
		    for (int k = 1; k <= 3; k++) 
		        G[i] = (G[i] + F[k] * D[i][k]) % modn;
		printf("%lld\n", (G[3] + modn) % modn);        
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值