• $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]
  • 相关阅读:
    dblink && 视图 数据库二合一
    oracle mybatis 逆向工程 应当注意的问题
    关于使用vue搭建前后端分离的项目,部署过程遇到的问题
    详解vue静态资源打包中的坑与解决方案
    bootstarap table 分页导出 vue版
    react中两个控件不是父子关系该怎么传递消息或任意控件怎么传递消息
    虚拟DOM中key的作用
    修改Antd的List列表的单个数据行
    移动端开发如何关闭手机键盘
    在一行显示两个数据,左边的数据右对齐,右边的数据左对齐
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11237138.html
Copyright © 2020-2023  润新知