【题目链接】
ybt 1870:【12NOIP提高组】国王游戏
洛谷 P1080 [NOIP 2012 提高组] 国王游戏
【题目考点】
1. 贪心算法
- 邻项交换法
假设最的贪心选择序列中存在相邻元素不符合贪心选择策略,证明如果将二者交换后结果更优或与之前相同,那么就可以不断交换这样的相邻元素直到序列符合贪心选择策略。
2. 高精度
【解题思路】
思路1:通过邻项交换法推测贪心选择
每个大臣可以抽象为一个元素,每个元素是一个数对,原序列中第
i
i
i个大臣左手的数为
l
i
l_i
li,右手的数为
r
i
r_i
ri。设
s
i
=
∏
j
=
1
i
l
j
s_i=\prod_{j=1}^{i}l_j
si=∏j=1ilj,将第
i
i
i个大臣获得的钱数叫做元素的特征值,为:
s
i
−
1
r
i
\dfrac{s_{i-1}}{r_i}
risi−1。大臣的排列就是元素序列。
所求结果为:对于所有元素的排列,存在一种排列,其各元素的最大特征值相比于其它排列的最大特征值是最小的。求该排列下各元素最大的特征值。
基于邻项交换法,思考贪心策略。
假设能取得最优解的的序列中,任选第
i
i
i元素,与其相邻的下一个元素为第
j
j
j元素。
第
i
i
i元素的特征值为:
s
i
−
1
r
i
\frac{s_{i-1}}{r_i}
risi−1,第
j
j
j元素的特征值为:
s
i
r
j
\frac{s_i}{r_j}
rjsi
在序列中交换第
i
i
i和第
j
j
j元素后:
第
i
i
i元素的特征值为:
s
i
r
i
\frac{s_i}{r_i}
risi
第
i
+
1
i+1
i+1元素的特征值为:
s
i
−
1
r
j
\frac{s_{i-1}}{r_j}
rjsi−1
由于交换前为最优解,因此要保证交换前第
i
i
i与
i
+
1
i+1
i+1元素的特征值的最大值小于等于交换后第
i
i
i与
i
+
1
i+1
i+1元素的特征值的最大值,因此:
m
a
x
(
s
i
−
1
r
i
,
s
i
r
j
)
≤
m
a
x
(
s
i
−
1
⋅
l
j
r
i
,
s
i
−
1
r
j
)
max(\dfrac{s_{i-1}}{r_i}, \dfrac{s_i}{r_{j}})\le max(\dfrac{s_{i-1}\cdot l_j}{r_i}, \dfrac{s_{i-1}}{r_{j}})
max(risi−1,rjsi)≤max(risi−1⋅lj,rjsi−1)
两边乘以
r
i
r
j
s
i
−
1
\dfrac{r_ir_j}{s_{i-1}}
si−1rirj,得:
m
a
x
(
r
j
,
l
i
r
i
)
≤
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j, l_ir_i)\le max(l_jr_j, r_i)
max(rj,liri)≤max(ljrj,ri)
sort排序的比较规则必须满足严格弱序具体原理见该博文:C++: Strict Weak Ordering。
而比较规则
m
a
x
(
r
j
,
l
i
r
i
)
≤
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j, l_ir_i)\le max(l_jr_j, r_i)
max(rj,liri)≤max(ljrj,ri)不满足严格弱序中的非自反性,因此需要得到一个符合该关系的更严格的偏序关系。
可以尝试使用
m
a
x
(
r
j
,
l
i
r
i
)
<
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j, l_ir_i)< max(l_jr_j, r_i)
max(rj,liri)<max(ljrj,ri),但该关系不满足不可比性传递性。
进一步分类讨论
m
a
x
(
r
j
,
l
i
r
i
)
≤
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j, l_ir_i)\le max(l_jr_j, r_i)
max(rj,liri)≤max(ljrj,ri)。
- 如果 r j < l i r i ∧ r i < l j r j r_j<l_ir_i\land r_i<l_jr_j rj<liri∧ri<ljrj:那么该关系等价于 l i r i ≤ l j r j l_ir_i\le l_jr_j liri≤ljrj
- 如果 r j < l i r i ∧ r i ≥ l j r j r_j<l_ir_i\land r_i\ge l_jr_j rj<liri∧ri≥ljrj:那么该关系等价于 l i r i ≤ r i l_ir_i\le r_i liri≤ri,已知 r i > 0 r_i>0 ri>0,所以该关系等价于 l i ≤ 1 l_i\le 1 li≤1。
- 如果 r j ≥ l i r i ∧ r i < l j r j r_j\ge l_ir_i\land r_i<l_jr_j rj≥liri∧ri<ljrj:那么该关系等价于 r j ≤ l j r j r_j\le l_jr_j rj≤ljrj,即 l j ≥ 1 l_j\ge1 lj≥1。
- 如果 r j ≥ l i r i ∧ r i ≥ l j r j r_j\ge l_ir_i\land r_i\ge l_jr_j rj≥liri∧ri≥ljrj,那么该关系等价于 r j ≤ r i r_j\le r_i rj≤ri
经过讨论得到线索,某些情况下原关系
m
a
x
(
r
j
,
l
i
r
i
)
≤
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j, l_ir_i)\le max(l_jr_j, r_i)
max(rj,liri)≤max(ljrj,ri)
等价于
l
i
r
i
≤
l
j
r
j
l_ir_i\le l_jr_j
liri≤ljrj,可以排序的比较关系必须满足非自反性,所以取
l
i
r
i
<
l
j
r
j
l_ir_i< l_jr_j
liri<ljrj。
那么猜测:只要相邻
i
,
j
i,j
i,j两项满足
l
i
r
i
<
l
j
r
j
l_ir_i<l_jr_j
liri<ljrj,那么一定满足
m
a
x
(
r
j
,
l
i
r
i
)
≤
m
a
x
(
l
j
r
j
,
r
i
)
max(r_j,l_ir_i)\le max(l_jr_j, r_i)
max(rj,liri)≤max(ljrj,ri)
已知 l i , r i , l j , r j l_i, r_i, l_j, r_j li,ri,lj,rj都为正整数,且满足 l i r i < l j r j l_ir_i<l_jr_j liri<ljrj。
- 如果
l
j
r
j
≥
r
i
l_j r_j\ge r_i
ljrj≥ri,那么
m
a
x
(
l
j
r
j
,
r
i
)
=
l
j
r
j
max(l_jr_j, r_i)=l_j r_j
max(ljrj,ri)=ljrj
- 如果 r j > l i r i r_j> l_i r_i rj>liri,那么 m a x ( r j , l i r i ) = r j max(r_j,l_ir_i)=r_j max(rj,liri)=rj。 m a x ( r j , l i r i ) ≤ m a x ( l j r j , r i ) max(r_j,l_ir_i)\le max(l_jr_j, r_i) max(rj,liri)≤max(ljrj,ri)为 r j ≤ l j r j r_j\le l_j r_j rj≤ljrj,即 l j ≥ 1 l_j\ge 1 lj≥1,表达式成立。
- 如果 r j ≤ l i r i r_j\le l_i r_i rj≤liri,那么 m a x ( r j , l i r i ) = l i r i max(r_j,l_ir_i)=l_ir_i max(rj,liri)=liri, m a x ( r j , l i r i ) ≤ m a x ( l j r j , r i ) max(r_j,l_ir_i)\le max(l_jr_j, r_i) max(rj,liri)≤max(ljrj,ri)为 l i r i ≤ l j r j l_i r_i\le l_j r_j liri≤ljrj,表达式成立。
- 如果 l j r j < r i l_j r_j< r_i ljrj<ri,已知 l i r i < l j r j l_ir_i<l_jr_j liri<ljrj,那么 r i < l j r j l i ≤ l j r j r_i<\frac{l_jr_j}{l_i}\le l_jr_j ri<liljrj≤ljrj,因此不存在 l j r j < r i l_j r_j< r_i ljrj<ri的情况。
因此可以将序列按照比较规则 l i r i < l j r j l_ir_i<l_jr_j liri<ljrj排序,而后进行贪心选择。
思路2: 直接猜测贪心策略
根据第
i
i
i元素的特征值为:
s
i
−
1
r
i
=
s
i
l
i
r
i
\dfrac{s_{i-1}}{r_i}=\dfrac{s_i}{l_ir_i}
risi−1=lirisi。
第
n
n
n个元素为
s
i
l
n
r
n
\dfrac{s_i}{l_nr_n}
lnrnsi,分子是固定的,第
n
n
n元素的两数乘积越大,特征值越小。所以第
n
n
n元素应该两数乘积最大,依次类推第
n
−
1
n-1
n−1元素的两数乘积倒数第二大。。。猜想应该按照每个元素的两数乘积排序,如果
i
,
j
i,j
i,j是相邻两项,那么相邻两项应该满足:
l
i
r
i
≤
l
j
r
j
l_ir_i\le l_{j}r_{j}
liri≤ljrj。
而后通过邻项交换法证明该贪心策略成立。
假设第
i
i
i元素和与其相邻的第
j
j
j元素(即第
i
+
1
i+1
i+1元素)不满足贪心策略,即
l
i
r
i
>
l
j
r
j
l_ir_i>l_{j}r_{j}
liri>ljrj
第
i
i
i元素的特征值为:
s
i
−
1
r
i
\dfrac{s_{i-1}}{r_i}
risi−1
第
j
j
j元素的特征值为:
s
i
r
j
\dfrac{s_i}{r_{j}}
rjsi
在序列中交换第
i
i
i和第
j
j
j元素后:
第
i
i
i元素的特征值为:
s
i
−
1
⋅
l
j
r
i
=
s
i
−
1
⋅
l
j
r
j
r
i
r
j
<
s
i
−
1
⋅
l
i
r
i
r
i
r
j
=
s
i
r
j
\dfrac{s_{i-1}\cdot l_{j}}{r_i}=\dfrac{s_{i-1}\cdot l_{j}r_{j}}{r_ir_{j}}<\dfrac{s_{i-1}\cdot l_{i}r_{i}}{r_ir_{j}}=\dfrac{s_i}{r_{j}}
risi−1⋅lj=rirjsi−1⋅ljrj<rirjsi−1⋅liri=rjsi
即第
i
i
i元素的特征值在交换后小于交换前第
j
j
j元素的特征值。
第
j
j
j元素的特征值为:
s
i
−
1
r
j
≤
s
i
r
j
\dfrac{s_{i-1}}{r_{j}} \le \dfrac{s_i}{r_{j}}
rjsi−1≤rjsi
即第
j
j
j元素的特征值在交换后小于等于交换前第
j
j
j元素的特征值。
因此两元素交换后,最大的特征值没有增大,仍然是最优解。可以不断交换不符合贪心选择顺序的相邻项,直到整个序列符合贪心策略。
因此贪心选择策略可以为:每次选择 l i r i l_ir_i liri最小的元素。具体做法是:将所有元素按 l i r i l_ir_i liri从小到大排序。而后计算各元素的特征值,比较求出各元素特征值的最大值,即为本题结果。
【题解代码】
解法1:每次选择 l i r i l_ir_i liri最小的元素
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1005;
struct Peo
{
int l, r;
} a[N];
struct HPN
{
int a[4100] = {};//1000个10000相乘,结果最多4000位
HPN(){}
HPN(int v)
{
int len = 0;
do
{
a[++len] = v%10;
v /= 10;
} while(v > 0);
a[0] = len;
}
int& operator [] (int i)
{
return a[i];
}
void setLen(int i)
{
while(a[i] == 0 && i > 1)
i--;
a[0] = i;
}
int numcmp(int *a, int *b)
{
if(a[0] > b[0])
return 1;
else if(a[0] < b[0])
return -1;
else
{
for(int i = a[0]; i >= 1; --i)
{
if(a[i] > b[i])
return 1;
else if(a[i] < b[i])
return -1;
}
return 0;
}
}
bool operator < (HPN b)
{
return numcmp(a, b.a) < 0;
}
void operator *= (int b)
{
int i, c = 0;
for(i = 1; i <= a[0]; ++i)
{
a[i] = a[i]*b+c;
c = a[i]/10;
a[i] %= 10;
}
while(c > 0)
{
a[i++] = c%10;
c /= 10;
}
setLen(i);
}
HPN operator / (int b)
{
HPN r;
int x = 0;
for(int i = a[0]; i >= 1; --i)
{
x = x*10+a[i];
r[i] = x/b;
x %= b;
}
r.setLen(a[0]);
return r;
}
void show()
{
for(int i = a[0]; i >= 1; --i)
cout << a[i];
cout << endl;
}
};
int n;
bool cmp(Peo a, Peo b)
{
return a.l*a.r < b.l*b.r;
}
int main()
{
cin >> n;
for(int i = 0; i <= n; ++i)//a[0]为国王
cin >> a[i].l >> a[i].r;
sort(a+1, a+1+n, cmp);//对所有大臣排序
HPN s(a[0].l), ans(0);
for(int i = 1; i <= n; ++i)
{
if(ans < s/a[i].r)
ans = s/a[i].r;
s *= a[i].l;
}
ans.show();
return 0;
}
8948

被折叠的 条评论
为什么被折叠?



