AcWing 114. 国王游戏

题面

总记

刚入手这道题似乎有些手足无措,是深搜求全排列,还是二分?

题意就是国王是个小气鬼。先分析样例,易得最佳序列如下:

1 1
2 3
4 6
7 4

通过样例会发现,只要\(a\)越小,\(b\)越大,那么国王付出的奖赏就越少,即便是奖赏最多的大臣奖赏也是所有情况中最少的。

但是\(a,b\)的关系很矛盾,更恰巧的是,\(a*b\)正好呈升序。
也就是说,该题的题意就是要我们用贪心的方法,证明出一种通式使得大臣获得奖赏整体都是最小的。

推导

常用的贪心方法,假设下面是国王最省钱的序列(序列不唯一):

a1 b1
a2 b2
……
a[i-1] b[i-1]
ai bi
……
an bn

且另有一新序列,只颠倒了a[i] b[i]和a[i-1] b[i-1]。

……
a[i-2] b[i-2]
ai bi
a[i-1] b[i-1]
……

那么除了第i和i-1位,其他位都是不变得。所以这两位当中,一定有一位或者两位都是,大于最佳序列的对应位的奖赏。

\(C1_i\)表示原序列第\(i\)位的奖赏,\(C2_i\)表示新序列第\(i\)位的奖赏,
计算得到:

\[C1_i = \frac{\prod_{j=1}^{i-1}a_j}{b_i} \ ≤ \ C2_i = \frac{\prod_{j=1}^{i-2}a_j * a_i}{b_{i-1}} \]

\[C1_{i-1} = \frac{\prod_{j=1}^{i-2}a_j}{b_{i-1}} \ ≤ \ C2_{i-1} = \frac{\prod_{j=1}^{i-2}a_j}{b_i} \]

通分:

\[\frac{a_{i-1}}{b_i} \ ≤ \ \frac{a_i}{b_{i-1}} \]

\[\frac{1}{b_{i-1}} \ ≤ \ \frac{1}{b_i} \]

由于b的大小无法比较,又因为这两位中必定有一位比原序列的大,所以2式片面舍去。

十字相乘后:

\[a_{i-1} * b_{i-1} ≤ a_i * b_i \]

至此原来的猜测得证了。猜想是贪心的第一步!

实现

注意观察数据,最多奖赏为\(10000^{1000}\),需要高精度。

先以a,b乘积从小到大排序,再从中找最大值

100 pts

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int> VI;
const int N = 1010;
int n;

struct pt{
    int a, b;
    bool operator <(const pt &t){ //乘积从小到大排序
        return a * b < t.a * t.b;
    }
}e[N];

/***高精度计算***/
VI mul(VI a, int b)
{
    VI res;
    int r = 0;
    for(int i = 0; i < a.size(); i ++ )
    {
    	r += a[i] * b ;
    	res.push_back(r % 10);
    	r /= 10;
	}
	while(r) res.push_back(r % 10), r /= 10;
    
    return res;
}

VI Div(VI a, int b)
{
    VI res;
    int r = 0;
    for(int i = a.size() - 1; i >= 0; i -- )
    {
    	r = r * 10 + a[i];
    	res.push_back(r / b);
    	r %= b;
	}
	reverse(res.begin(), res.end());
    
    return res;
}

VI imax(VI a, VI b)
{
	if(a.size() != b.size())
	{
		if(a.size() > b.size()) return a;
		else return b;
	}
	for(int i = 0; i < a.size(); i ++ )
	{
		if(a[i] > b[i]) return a;
		else if(a[i] < b[i]) return b;
	}
}

VI tmul, res, t;
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	
	cin >> n;
	
	for(int i = 0; i <= n; i ++ ) cin >> e[i].a >> e[i].b;
	
	sort(e + 1, e + n + 1);
	
	tmul.push_back(1), res.push_back(0);
	// mul *= aj, mul /= bj
	for(int i = 0; i <= n; i ++ )
	{
	    tmul = mul(tmul, e[i].a);
	    if(i)
	    {
	        t = Div(tmul, e[i].b * e[i].a);
	        res = imax(res, t);
	    }
	}
	while(!res.back()) res.pop_back();
	for(int i = res.size() - 1; i >= 0; i -- ) cout << res[i];
	
	return 0;
}
posted @ 2023-01-27 21:37  Sankano  阅读(16)  评论(0编辑  收藏  举报