「Andrey and Problem」题解

本文介绍了一种通过排序和逆向遍历来确定最优集合的选择算法,并通过数学推导证明了其正确性。该算法适用于寻找最大乘积收益的问题场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做法超级简单,先从小到大排序,然后从后向前扫,选上更优就选上,不然就 breakbreakbreak


证明。

反证法:假设选择集合不是后缀

假设现在有一个选择集合 SSS(存储的是下标),找到这个集合出现的空隙(即 i∉S,i−1∈Si \notin S,i-1\in Si/S,i1S)。

T=∁S{i−1}T = \complement_S\{i - 1\}T=S{i1}

f(P)=Π(1−xpi),g(P)=∑xpi1−xpi,a=xi,b=xi−1f(P) = \Pi(1 - x_{p_i}), g(P) = \sum \frac{x_{p_i}}{1 - x_{p_i}},a = x_i, b = x_{i - 1}f(P)=Π(1xpi),g(P)=1xpixpi,a=xi,b=xi1

则有:a>ba > ba>b

容易得到计算答案的式子: f(P)∗g(P)f (P) * g (P)f(P)g(P)

即证 f(T⋃{i})∗g(T⋃{i})>f(T⋃{i−1})∗g(T⋃{i−1})f(T \bigcup \{i\}) * g(T \bigcup \{i\}) > f(T \bigcup \{i - 1\}) * g(T \bigcup \{i - 1\})f(T{i})g(T{i})>f(T{i1})g(T{i1})

即证 f(T)∗(1−a)∗(g(T)+a1−a)>f(T)∗(1−b)∗(g(T)+b1−b)f(T) * (1 - a) * (g (T) + \frac{a}{1-a}) > f(T) * (1 - b) * (g (T) + \frac{b}{1-b})f(T)(1a)(g(T)+1aa)>f(T)(1b)(g(T)+1bb)

即证 f(T)∗g(T)∗(1−a)+a1−a∗(1−a)∗f(T)>f(T)∗g(T)∗(1−b)+b1−b∗(1−b)∗f(T)f(T) * g (T) * (1 - a) + \frac{a}{1 - a} * (1 - a) * f (T) > f(T) * g (T) * (1 - b) + \frac{b}{1 - b} * (1 - b) * f (T)f(T)g(T)(1a)+1aa(1a)f(T)>f(T)g(T)(1b)+1bb(1b)f(T)

即证 f(T)∗g(T)∗(1−a)+a∗f(T)>f(T)∗g(T)∗(1−b)+b∗f(T)f(T) * g (T) * (1 - a) + a * f (T) > f(T) * g (T) * (1 - b) + b * f (T)f(T)g(T)(1a)+af(T)>f(T)g(T)(1b)+bf(T)

即证 g(T)−g(T)∗a+a>g(T)−g(T)∗b+bg (T) - g (T) * a + a > g (T) - g (T) * b + bg(T)g(T)a+a>g(T)g(T)b+b

即证 (1−g(T))∗a>(1−g(T))∗b(1 - g (T)) * a > (1 - g (T)) * b(1g(T))a>(1g(T))b

又∵1>g(T)>0,a>b又\because 1 > g (T) > 0, a > b1>g(T)>0,a>b

得证。


#include <map>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
template <typename T>
void read (T &x) {
	x = 0; T f = 1;
	char ch = getchar ();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar ();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + ch - '0';
		ch = getchar ();
	}
	x *= f;
}
template <typename T>
void write (T x) {
	if (x < 0) {
		x = -x;
		putchar ('-');
	}
	if (x < 10) {
		putchar (x + '0');
		return;
	}
	write (x / 10);
	putchar (x % 10 + '0');
}
template <typename T>
void print (T x, char ch) {
	write (x); putchar (ch);
}

const int Maxn = 100;
const double eps = 1e-10;

int n;
double a[Maxn + 5];

int main () {
//	freopen (".in", "r", stdin);
//	freopen (".out", "w", stdout);
	cin >> n; for (int i = 1; i <= n; i++) cin >> a[i];
	sort (a + 1, a + 1 + n);
	if (Abs (a[n] - 1) < eps) {
		printf ("%.12lf", 1.0);
		return 0;
	}
	double t = 1, tot = 0;
	for (int i = n; i >= 1; i--) {
		if (t * (1 - a[i]) * (tot + a[i] / (1 - a[i])) < t * tot)
			break;
		t *= (1 - a[i]);
		tot += a[i] / (1 - a[i]);
	}
	printf ("%.12lf", t * tot);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值