(Luogu) P1080 国王游戏 (贪心)

本文探讨了一种关于大臣排序的问题,通过分析大臣的左右手能力,提出了一种优化算法。通过对大臣的能力值进行特殊处理和排序,实现了更高效的计算。文章详细介绍了算法的实现过程,并提供了两种不同的代码实现方案。

传送门

解题思路:一开始单纯的直接按照左手升序或者右手降序,这种想法必然是不准确的,但是能得30分,那么应该如何判断哪些大臣应该被排在前面呢,现在我们不如直接从所有的大臣种先选出两位来判断。

属性左手右手
皇上X1Y1
大臣甲X2Y2
大臣乙X3Y3

 

如果是这样的话,那答案就是有两种排序方式max(X1/Y2,X1*X2/Y3),max(X1/Y3,X1*X3/Y2) 取个最小值即为答案。

k1=X1/Y2,k2=X1*X2/Y3

k3=X1/Y3,k4=X1*X3/Y2, 首先可以很容易的判断出   k4>k1, k2>k3的;现在假设第一种排序方式更好,即最大值最小,那就只需要k2<k4就行了,那第一种排序的两个都比第二种小了。化简一下就是X2*Y2<X3*Y3;

但是有序左右相乘乘出来的数非常大,用unsigned long long 也只有60分。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int n;
struct node {
	ull a,b,c;
} t[1010];
ull s,ans;
bool cmp(node a,node b) {
	return a.c<b.c;
}
int main() {
	std::ios::sync_with_stdio(false);
	cin>>n;
	for(int i=0; i<=n; i++) {
		cin>>t[i].a>>t[i].b,t[i].c=t[i].a*t[i].b;
	}
	sort(t+1,t+1+n,cmp);
	s=t[0].a;
	for(int i=1; i<=n; i++) {
		ans=max(ans,s/t[i].b),s*=t[i].a;
	}
	cout<<ans;
}

高精度不想写了,咕咕咕。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1005;
struct Nodes {
	int l, r;
	bool operator < (const Nodes &rhs) const {
		return l * r < rhs.l * rhs.r;
	}
} s[maxn];
int n;
int L, R;
struct INT {
	int a[10005], len;
	INT() {
		memset(a, 0, sizeof a);
		len = 0;
	}
	void init(int x) {
		if(x == 0) len = 1;
		else {
			while(x) {
				a[len++] = x % 10;
				x /= 10;
			}
		}
	}
	bool operator < (const INT &rhs) const {
		if(len != rhs.len) return len < rhs.len;
		for(int i = len - 1; i >= 0; i--) {
			if(a[i] < rhs.a[i]) return true;
			else if(a[i] > rhs.a[i]) return false;
		}
		return false;
	}
	INT operator * (const int &rhs) const {
		INT ret;
		for(int i = 0; i < len; i++) ret.a[i] = a[i] * rhs;
		int llen;
		for(int i = 0; i < len || ret.a[i]; i++) {
			if(ret.a[i] / 10) {
				ret.a[i + 1] += ret.a[i] / 10;
				ret.a[i] %= 10;
			}
			llen = i;
		}
		if(ret.a[llen] == 0) ret.len = llen;
		else ret.len = llen + 1;
		return ret;
	}
	INT operator / (const int &x) const {
		INT ret;
		ret.len = len;
		int rest = 0;
		for(int i = len - 1; i >= 0; i--) {
			rest = rest * 10 + a[i];
			ret.a[i] = rest / x;
			rest %= x;
		}
		while(ret.len > 1 && ret.a[ret.len - 1] == 0) ret.len--;
		return ret;
	}
	void print() {
		for(int i = len - 1; i >= 0; i--) printf("%d", a[i]);
		printf("\n");
	}
};
int main() {

	scanf("%d%d%d", &n, &L, &R);
	for(int i = 1; i <= n; i++) scanf("%d%d", &s[i].l, &s[i].r);
	std::sort(s + 1, s + n + 1);
	INT temp;
	temp.init(L);
	INT ans;
	for(int i = 1; i <= n; i++) {
		ans = std::max(ans, temp / s[i].r);
		temp = temp * s[i].l;
	}
	ans.print();
	return 0;

}

 

洛谷P1177是【模板】排序题,可使用归并排序来解决。归并排序的核心思想是分治法,即将一个大问题分解为多个小问题,分别解决后再合并结果。 归并排序主要步骤如下: 1. **分解**:将待排序数组从中间分成两个子数组,递归地对这两个子数组进行排序。 2. **合并**:将两个已排序的子数组合并成一个有序数组。 以下是使用归并排序解决洛谷P1177题目的代码实现: ```cpp #include<bits/stdc++.h> #include<iomanip> using namespace std; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const int MAXN = 1e5 + 5; int a[MAXN], b[MAXN]; int n; // 数组长度 // 合并两个已排序的子数组 void mergesort(int l1, int r1, int l2, int r2) { int i = l1, j = l2, k = l1; while (i <= r1 && j <= r2) { if (a[i] <= a[j]) { b[k++] = a[i++]; } else { b[k++] = a[j++]; } } while (i <= r1) b[k++] = a[i++]; while (j <= r2) b[k++] = a[j++]; for (i = l1; i <= r2; i++) { a[i] = b[i]; } } // 递归进行归并排序 void merge(int l, int r) { if (l >= r) { return; } int mid = (l + r) / 2; merge(l, mid); merge(mid + 1, r); mergesort(l, mid, mid + 1, r); } int main() { IOS; cin >> n; for (int i = 0; i < n; i++) { cin >> a[i]; } merge(0, n - 1); for (int i = 0; i < n; i++) { cout << a[i]; if (i < n - 1) cout << " "; } cout << endl; return 0; } ``` 上述代码中,`merge`函数用于递归地将数组分解为子数组,`mergesort`函数用于合并两个已排序的子数组。在`main`函数中,首先读取输入的数组,然后调用`merge`函数进行排序,最后输出排序后的数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值