$Luogu$ $P1080$ 国王游戏

链接

背景

(CCF) (NOIP2012) (Day1) (T2)(Luogu) (P1080)

题意

给定国王和 (n) 个大臣左右手上的金币数 (a)(b) 。每个大臣 (i) 获得金币为 (国王左手金币数 imes frac{prod_{j=1}^{i-1} a[j]}{b[i]}) ,请设计一个排队顺序使得到金币数最多的大臣获得的金币数最小,注意国王只能在队首。

解法

设国王所在位置为 (0) ,则每个大臣 (i) 获得金币为 (frac{prod_{j=0}^{i-1} a[j]}{b[i]}) 。贪心策略为按 (a[i] imes b[i]) 从小到大排序算结果即可。
证明:微扰法(邻项交换法)。
考虑连续的两个大臣 (i)(i+1) ,假设交换 (i)(i+1) 的位置,则对于 (i) 以前的大臣获得的金币数没有影响,对于 (i+1) 以后的大臣获得的金币数也没有影响。
在交换以前, (i) 获得的金币数为 (frac{prod_{j=0}^{i-1} a[j]}{b[i]})(i+1) 获得的金币数为 (frac{prod_{j=0}^{i} a[j]}{b[i+1]}) 。而交换以后 (i) 获得的金币数为 (frac{prod_{j=0}^{i} a[j]}{b[i]})(i+1) 获得的金币数为 (frac{prod_{j=0}^{i-1} a[j]}{b[i+1]})
为了比较大小,约去公因式 (prod_{j=0}^{i-1} a[j]) ,则 (i) 交换前为 (frac{1}{b[i]})(i+1) 交换前为 (frac{a[i]}{b[i+1]})(i) 交换后为 (frac{a[i+1]}{b[i]})(i+1) 交换后为 (frac{1}{b[i+1]})
发现还是不便于比较,将四个数同时乘以 (b[i] imes b[i+1]) ,则 (i) 交换前为 (b[i+1])(i+1) 交换前为 (a[i] imes b[i])(i) 交换后为 (a[i+1] imes b[i+1])(i+1) 交换后为 (b[i])
已知金币数为正整数,故 (a[i] imes b[i] > b[i])(a[i+1] imes b[i+1] > b[i+1]) ,而题目中答案只要求最大金币数最小,因此只需要比较 (a[i] imes b[i])(a[i+1] imes b[i+1]) 即可。
情况一: (a[i] imes b[i] geqslant a[i+1] imes b[i+1]) 时,交换不会使得答案变小,因此可以交换;
情况二: (a[i] imes b[i] leqslant a[i+1] imes b[i+1]) 时,交换不会使得答案变大,因此不要交换。
那么,使得整个队伍都有 (a[i] imes b[i] leqslant a[i+1] imes b[i+1]) 时,答案最小。
综上,贪心策略成立。

(trick)

以排序为贪心策略的题目大概率是用微扰法(邻项交换法)证明的。最终结果的序列一定不能通过交换使得答案变大。

细节

(1.) 每个大臣进队时,乘入结果的是上一个大臣左手上的数,除以的是自己手上的数。

(2.) 此题只有 (60\%) 的数据答案在 (10^9) 以内,其余的均要使用高精度解决。高精度模板

代码

$View$ $Code$ ```cpp #include using namespace std; inline int read() { int ret=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { ret=(ret<<1)+(ret<<3)+ch-'0'; ch=getchar(); } return ret*f; } int n,lens=1,lenm=1,lena=1,sum[10005]={0,1},maxn[10005]={0,1},ans[10005]; struct node { int a; int b; }s[1005]; inline bool cmp(node x,node y) { return x.a*x.b=x) { ans[i]=tmp/x; tmp%=x; } } while(ans[lena]==0) { if(lena==1) break; lena--; } } inline void cmp1() { if(lena>lenm) { for(register int i=1;i<=lena;i++) maxn[i]=ans[i]; lenm=lena; } else if(lenm==lena) { for(register int i=lena;i;i--) { if(maxn[i]
原文地址:https://www.cnblogs.com/Peter0701/p/11237138.html