标签:als 快排 如何 lin spl 解法 init include 大小
这道题人云亦云说是贪心。但是重点是如何证明贪心是对的。
需要给定一定的排列来使拿到最多钱的大臣拿的最少,其实就是个排序。
我们讨论两个前后关系的大臣,如何才能使答案最小。
设两位大臣一位叫\(a\),一位叫\(b\),把他们前面的人(包括国王)的左手的乘积统称为\(tot\)。
当\(a\)排在\(b\)前面,则\(a\)得到的钱是\(\frac{tot}{r_a}\),\(b\)得到的钱是\(\frac{tot \times l_a}{r_b}\)。
而当\(b\)排在\(a\)前面,则\(b\)得到的钱是\(\frac{tot}{r_b}\),\(a\)得到的钱是\(\frac{tot \times l_b}{r_a}\)。
显然,第一种情况\(b\)拿到的钱比第二种情况\(a\)拿的钱多,并且第二种情况\(b\)拿到的钱比第一种情况\(a\)拿到的钱多。
所以这两对大小关系我们根本不需要去比较。。。
现在设第二种情况更优。
那么一定会有\(\frac{tot \times l_b}{r_a} < \frac{tot \times l_a}{r_b}\),可以约掉\(tot\),再同乘以\(r_ar_b\),就可以得到
\[l_b \times r_b < l_a \times r_a\]
所以在两者之间,左手乘右手的积较小的,答案会更小。
这样的证明可以在冒泡排序中成立,那么其他排序呢?
也成立!难道冒泡成立的,快排就不成立啦?!
所以这就是这道题的解法:按照左手乘以右手的积从小到大排序,每个人算下自己拿的钱,取max即可。
然后要命的来了:这道题需要高精度!
不过也是简单的高精度。因为这道题只需要处理高精乘低精和高精除以低精这两种操作,重载运算符即可搞定。
因为我之前根本没掌握过这些高精低精互相运算的东西,所以也抄了别人的题解。。。
代码:
#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()
{
/*
while(233)
{
int x, y; scanf("%d%d", &x, &y);
INT xx; xx.init(x);
INT yy; yy.init(y);
INT res1 = xx * y, res2 = xx / y;
res1.print();
res2.print();
printf("%d\n", xx < yy);
}
return 0;
*/
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;
}
标签:als 快排 如何 lin spl 解法 init include 大小
原文地址:https://www.cnblogs.com/Garen-Wang/p/9813320.html