当前位置: 首页 > article >正文

【2024.2.4练习】国王游戏

题目描述


题目思路

涉及排列组合求最优解问题,数据大考虑是否满足某种贪心策略。

假设不除以右手的数字,那么获得金币数量最多的显然为最后一个人。左手数字最大的应排在最后一位。在右手有数字的情况下,不妨也尝试从最后一个人开始排。

假设最后一个为第n个人(国王为第0个),他左手和右手上的数字分别为L_nR_n,他获得的金币为G_n。则:

①  G_n= L_0\times \frac{L_1\times L_2\times ...\times L_{n-1}}{R_n}

假设将他和第一个大臣交换位置,则最后一个获得的金币变成:
②  {G_n}' = L_0\times \frac{L_n\times L_2\times ...\times L_{n-1}}{R_1}

将①式与②式相除,得:
③  \frac{G_n}{G_n{}'} =\frac{L_1\times R_1}{L_n\times R_n}

要使最后一个人获得的金币数尽可能少,应使G_n\leq G_n{}',则L_nR_n应尽可能大。

现在我们已经知道了使最后一个获得金币最少的策略。接下来需证明所有人都用这种策略就能使最大金币数最小。假设最后一个人可能获得金币的数量有k种,分别为A_1,A_2,A_3...A_{k},分别对应第k个人在最后一个位置上时获得金币数。倒数第二个人可能获得金币的数量有k-1种,分别为B_1,B_2,B_3...B_{k-1},因为已经有一个人排到了最后一个位置上。

易证:A_i> B_i

因此,每次应选取A_i中最小的那一个,这样剩余的A_i在转化成B_i时值都会减小,按此策略选择出的最大金币数也是最小的。

还有一个细节,当两个L_nR_n的值相同的时候应先排哪个?
L_iR_i=L_jR_j,设先排L_iR_i,则:

G_i= L_0\times \frac{L_1\times L_2\times ...\times L_{j-1}\times L_{j}}{R_i}

G_j= L_0\times \frac{L_1\times L_2\times ...\times L_{j-1}}{R_j}

两式相除得:\frac{G_i}{G_j} =\frac{L_j\times R_j}{R_i}=L_i

可以看出后排获得得金币数G_j=G_i/L_i,为了使后一个获得的金币数尽可能少,故两个L_nR_n的值相同的时候应先排L_n更高的。


我的代码

为了求ab的最大值,需要在执行贪心策略的过程中使用排序算法,由于排序中涉及两个变量,故采用map容器排序,时间复杂度为O(nlogn)。由于部分数据范围需要高精度算法。高精度部分尚未实现

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
typedef multiset<int> s;
typedef pair<int, s> p;
map<int, s> m;
map<int, s>::iterator it;
multiset<int>::iterator it2;
int a[1001];
int b[1001];
int main() {
	int n;
	//快速排序
	cin >> n;
	cin >> a[0] >> b[0];
	for (int i = 1; i <= n; i++)
	{
		s S;
		cin >> a[i] >> b[i];
		S.insert(a[i]);
		//向map容器插入数据
		pair<map<int, s>::iterator, bool> flag = m.insert(p(a[i] * b[i], S));
		//检查元素是否冲突(ab相等)
		if (!flag.second) {
			s S2((*flag.first).second);
			S2.insert(a[i]);
			m.erase(flag.first);
			m.insert(p(a[i] * b[i], S2));
		}
	}
	//执行贪心
	long long mult = a[0];
	long long ans = 0;
	for (it = m.begin(); it != m.end(); it++) {
		s S((*it).second);
		for (it2 = S.begin(); it2 != S.end(); it2++) {
			long long L = *it2;
			//cout << L;
			long long R = (*it).first / L;
			//cout << R;
			ans = max(ans, (mult / R));
			mult = mult * L;
		}
	}
	cout << ans<< endl;
	return 0;
}

http://www.kler.cn/a/227667.html

相关文章:

  • 一页纸教你了解Git工作流程
  • 编曲学习:和弦编配(下) 和弦进行 转位和弦 Leading bass
  • Linux 驱动开发基础知识——总线设备驱动模型(七)
  • 创建TextMeshPro字体文件
  • 使用_NT_SYMBOL_PATH在启动VS前设置PDB路径
  • openGauss学习笔记-213 openGauss 性能调优-总体调优思路
  • [SWPUCTF 2021 新生赛]easyupload1.0
  • 设计模式——职责链模式(Chain of Responsibility Pattern)
  • 【开源】基于JAVA+Vue+SpringBoot的河南软件客服系统
  • 详解C++类和对象(上)
  • elk之基础概念
  • UnityShader(十三)Unity内置的函数
  • AJAX-URL查询参数
  • 【译】在 Mac 上加速 PyTorch 训练
  • 海量数据处理商用短链接生成器平台 - 2
  • 海外盲盒系统搭建,加快盲盒企业出海进程
  • MySQL进阶之事务
  • Flask 入门5 :过滤器
  • 【SparkML系列1】相关性、卡方检验和概述器实现
  • 软件需求分析报告