联盟周赛J题 集合的最小值

联盟周赛J题 集合的最小值

题目链接

https://nanti.jisuanke.com/t/40859

解题思路

这道题目要求的是所有集合的最大值和最小值的乘积的和,所以只需要关注最小值和最大值。
我们现在假设集合中有4个数:2、5、8、10
ps:我们先不考虑像 ( 2 , 2 ) (2,2) (2,2) 这样的特殊情况。
首先看第一个数2,以2为最大值构成不了集合。

接着看第二个数5,以5为最大值构成的集合有:
( 2 , 5 ) (2,5) (2,5):最小值是2。

接着看第三个数8,以8为最大值构成的集合有:
( 2 , 8 ) , ( 2 , 5 , 8 ) (2,8),(2,5,8) (2,8),(2,5,8):最小值是2。
( 5 , 8 ) (5,8) (5,8) :最小值是5。

最后看第四个数10,以10为最大值构成的集合有:
( 2 , 10 ) , ( 2 , 5 , 10 ) , ( 2 , 8 , 10 ) , ( 2 , 5 , 8 , 10 ) (2,10),(2,5,10),(2,8,10),(2,5,8,10) (2,10),(2,5,10),(2,8,10),(2,5,8,10):最小值是2。
( 5 , 10 ) , ( 5 , 8 , 10 ) (5,10),(5,8,10) (5,10),(5,8,10):最小值是5。
( 8 , 10 ) (8,10) (8,10):最小值是8。

上面的枚举是以最大值为标准展开的,除了像 ( 2 , 2 ) (2,2) (2,2) 这样的特殊情况,其他的集合都枚举出来了。我们来看第二次和第三次枚举之间的关系,第二次枚举最小值只有2,且2只出现1次;第三次枚举最小值2出现了2次;第四次枚举最小值2出现了4次,并且最小值5出现了2次,是第三次枚举的2倍。
由此可以看出相邻两次枚举最小值的和之间的关系了:第i次枚举出现的最小值的和 = 第i-1次枚举出现的最小值的和的2倍 + 第i-1大的值。

上面的结论是建立在最先给出的数是按升序排列的,当然,我们可以对题目给的数排序。

我们来看2倍是怎么出现的:以第三次和第四次枚举为例,第三次枚举2和8之间有一个数5,当以2为最小值,8为最大值时,只有两种选择,选5和不选5;第四次枚举2和10之间有两个数5和8,这两个数各有两个选择,选或不选,这样就是4种选择。

接下来就可以写代码了:用 a 存储输入,dp[i] 表示以 a[i] 为(a 已排过序)最大值所能确定的集合的最小值之和。有如下递推式 dp[i]=dp[i-1]*2 + a[i-1],最终结果是 ∑ 0 n − 1 ( d p [ i ] ∗ a [ i ] + a [ i ] ∗ a [ i ] ) \sum_0^{n-1}(dp[i] * a[i] + a[i]*a[i]) 0n1(dp[i]a[i]+a[i]a[i]) a [ i ] ∗ a [ i ] a[i]*a[i] a[i]a[i] 表示集合只有一个的特殊情况。
ps:dp[0]的值为0,因为不存在以a[0]为最大值的集合
源代码如下:

#include <cstdio> 
#include <iostream>
#include <algorithm>
#define NUM 100500
#define MOD 1000000007
#define ll long long
using namespace std;

ll dp[NUM];
ll a[NUM];

ll solve(int n) {
	for (int i = 1; i < n; ++i) {
		dp[i] = (2*dp[i-1] + a[i-1]) % MOD;
	}
	ll res = 0;
	for (int i = 0; i < n; ++i) {
		res = (res + dp[i]*a[i] % MOD + a[i]*a[i] % MOD) % MOD;
	}
	return res;
}

int main(int argc, char** argv) {
	int n;
	cin >> n; 
	for (int i = 0; i < n; ++i) {
		scanf("%lld", a+i);
	}
	sort(a, a+n);
	ll res = solve(n);
	printf("%lld\n", res);
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值