【ybtoj】【贪心】【数学】【高精度】【例题4】国王游戏

【例题4】国王游戏


>link

传送门
题目


>解题思路

左手为 X i X_i Xi,右手为 Y i Y_i Yi
S i = ∏ j = 1 i x i S_i=\prod^i_{j=1}x_i Si=j=1ixi
考虑相邻的两个大臣的交换

交换前 交换后
i i i个大臣 S i − 1 Y i \frac{S_{i-1}}{Y_i} YiSi1 S i − 1 Y i + 1 \frac{S_{i-1}}{Y_{i+1}} Yi+1Si1
i + 1 i+1 i+1个大臣 S i − 1 ∗ X i Y i + 1 \frac{S_{i-1}*X_i}{Y_{i+1}} Yi+1Si1Xi S i − 1 ∗ X i + 1 Y i \frac{S_{i-1}*X_{i+1}}{Y_i} YiSi1Xi+1

m i n ( m a x ( S i − 1 Y i , S i − 1 ∗ X i Y i + 1 ) , m a x ( S i − 1 Y i + 1 , S i − 1 ∗ X i + 1 Y i ) ) min(max(\frac{S_{i-1}}{Y_i},\frac{S_{i-1}*X_i}{Y_{i+1}}),max(\frac{S_{i-1}}{Y_{i+1}},\frac{S_{i-1}*X_{i+1}}{Y_i})) min(max(YiSi1,Yi+1Si1Xi)max(Yi+1Si1,YiSi1Xi+1))
以下化简公式
两边除以 S i − 1 S_{i-1} Si1
m i n ( m a x ( 1 Y i , X i Y i + 1 ) , m a x ( 1 Y i + 1 , X i + 1 Y i ) ) min(max(\frac{1}{Y_i},\frac{X_i}{Y_{i+1}}),max(\frac{1}{Y_{i+1}},\frac{X_{i+1}}{Y_i})) min(max(Yi1,Yi+1Xi)max(Yi+11,YiXi+1))
去分母,两边乘上 ( Y i ) ( Y i + 1 ) (Y_i)(Y_{i+1}) (Yi)(Yi+1)
m i n ( m a x ( Y i + 1 , X i ∗ Y i ) , m a x ( Y i , X i + 1 ∗ Y i + 1 ) ) min(max(Y_{i+1},X_i*Y_i),max(Y_i,X_{i+1}*Y_{i+1})) min(max(Yi+1,XiYi)max(Yi,Xi+1Yi+1))
m i n ( m a x ( a 2 , b 1 ) , m a x ( a 1 , b 2 ) ) min(max(a2,b1),max(a1,b2)) min(max(a2,b1),max(a1,b2))

很容易发现
Y i < X i ∗ Y i Y_i<X_i*Y_i Yi<XiYi

Y i + 1 < X i + 1 ∗ Y i + 1 Y_{i+1}<X_{i+1}*Y_{i+1} Yi+1<Xi+1Yi+1

= = =

a 1 < b 1 a1<b1 a1<b1

a 2 < b 2 a2<b2 a2<b2
在有比较性的搭配中,只有最终 b 1 b1 b1 b 2 b2 b2的比较
m i n ( X i ∗ Y i , X i + 1 ∗ Y i + 1 ) min(X_i*Y_i,X_{i+1}*Y_{i+1}) min(XiYi,Xi+1Yi+1)

那么就是任意的 X i ∗ Y i X_i*Y_i XiYi X i + 1 ∗ Y i + 1 X_{i+1}*Y_{i+1} Xi+1Yi+1小(不交换)的队伍是最优的
//(如果要交换的话,排出来的队伍就不是最优的)
也就是按照 X ∗ Y X*Y XY从小到大的排序

S S S的最大数值是 100 0 10000 1000^{10000} 100010000,要高精度: )


>Code

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

using namespace std;

const int maxn = 10000;
struct DT {
    
    
	int x, y, s;
} a[1010];
int n, ax, ay, s[maxn + 10], tpy[maxn + 10], ans[maxn + 10];

bool cmp(const DT& k, const DT& l) {
    
     return k.s < l.s; }

void cheng(int x) {
    
    //高精乘
	int g = 0;
	for (int i = maxn; i; i--) {
    
    
		s[i] = s[i] * x + g;
		g = s[i] / 10;
		s[i] %= 10;
	}
}

void chu(int x) {
    
    //高精除
	memset(tpy, 0, sizeof(tpy));
	long long g = 0;
	int i = 1;
	while (i <= maxn && s[i] == 0) i++;
	for (; i <= maxn; i++) {
    
    
		g = g * 10 + s[i];
		if (g >= x) {
    
    
			tpy[i] = g / x;
			g %= x;
		}
	}
}

void replace(int x) {
    
    //更新max
	for (int i = x; i <= maxn; i++) ans[i] = tpy[i];
}

void compare() {
    
    //比较当前max和当前大臣的奖励数
	int i = 1;
	while (i <= maxn && tpy[i] == 0) i++;//当前大臣的奖励数
	int j = 1;
	while (j <= maxn && ans[j] == 0) j++;//当前max
	if (i < j)
		replace(i);
	for (; i <= maxn; i++, j++)
		if (tpy[i] > ans[j]) {
    
    
			replace(i);
			return;
		} else if (tpy[i] < ans[j])
			return;
}

void print() {
    
    
	int i = 1;
	while (i <= maxn && ans[i] == 0) i++;
	while (i <= maxn) {
    
    
		printf("%d", ans[i]);
		i++;
	}
}

int main() {
    
    
	scanf("%d%d%d", &n, &ax, &ay);
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%d%d", &a[i].x, &a[i].y);
		a[i].s = a[i].x * a[i].y;
	}
	sort(a + 1, a + 1 + n, cmp);
	s[maxn] = 1;
	cheng(ax);//国王
	for (int i = 1; i <= n; i++) {
    
    
		chu(a[i].y);//算出当前大臣的奖励
		compare();//比较max
		cheng(a[i].x);//乘左手
	}
	print();
}

猜你喜欢

转载自blog.csdn.net/qq_39940018/article/details/111723252
今日推荐