NOIP2012 国王游戏 题解
描述
恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这n位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
格式
输入格式
第一行包含一个整数n,表示大臣的人数。
第二行包含两个整数a和b,之间用一个空格隔开,分别表示国王左手和右手上的整数。接下来n行,每行包含两个整数a和b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
样例1
样例输入1[复制]
3 1 1 2 3 7 4 4 6
样例输出1[复制]
2
限制
每个测试点1s
提示
对于20%的数据,有1≤ n≤ 10,0 < a、b < 8;
对于40%的数据,有1≤ n≤20,0 < a、b < 8;
对于60%的数据,有1≤ n≤100;
对于60%的数据,保证答案不超过10^9;
对于100%的数据,有1 ≤ n ≤1,000,0 < a、b < 10000。
贪心证明
假设相邻的两个人左右手分别是(a, b), (A, B)。设a * b <= A * B,i之前所有人的左手乘积为S。
则,ans1 = max{S / b, S * a / B}
若交换
则,ans2 = max{S / B, S * A / b}
因为,a * b <= A * B
所以,S * a / B <= S * A / b
又因为,S / B <= S * a / B
所以,ans2 = S * A / b
ans1 = max{S / B[i], S * a / B}
所以,ans1 <= ans2
证毕
解一:
首先我们分析一下如果i和j两个相邻那么i排在j前面的必要条件是 total *a[i] / b[j] < total * a[j] /b[i] 也就是说 a[i]*b[i] <a[j]*b[j]
而本题中,n《1000,a,b《10000 1000个10000乘起来。。。。
所以要用高精度,而高精度是以字符读入,那前面的排序要用一遍,麻烦。。。
所以本段程序有了改进:平时的精度数组只存一个一位数,这段程序存了每个大臣的数,每一次乘完都更新一遍,这样以后就可以读入时就处理好先后顺序,程序还很短。
【程序】
var i,n,l:longint; //l表示高精度中字符串的长度
a,b,c:array[0..100001] of longint; //a表示乘积,b表示左手,c表示右手
g:array[0..1000000] of longint;
procedure gj1; //高精乘
varj:longint;
begin
forj:=1 to l do g[j]:=g[j]*b[i]; //每一个都乘
forj:=1 to l do
begin
g[j+1]:=g[j+1]+g[j] div 10; //进位
g[j]:=g[j] mod 10; //进位后处理
end;
inc(l); //长度加一
while g[l]>9 do
begin
g[l+1]:=g[l+1]+g[l] div 10; //单个位上》9 进位
g[l]:=g[l] mod 10; //进位后处理
inc(l); //长度加一
end;
ifg[l]=0 then dec(l); //数组末位(数的首位)为0,出数组
end;
procedure gj2; //除法
var j:longint;
begin
forj:=l downto 1 do
begin
g[j-1]:=g[j-1]+(g[j] mod c[n])*10; //将前一位mod 第n位大臣右手给下一位(对于数来说)
g[j]:=g[j] div c[n]; //处理这一位
end;
while g[l]=0 do dec(l); //处理首位
ifl=0 then writeln('1'); //防止减完
end;
procedure qsort(l,r:longint); //快排
vari,j,x,y:longint;
begin
i:=l;
j:=r;
x:=a[(l+r) div 2];
repeat
while a[i]<x do inc(i);
while x<a[j] do dec(j);
if i<=j then
begin
y:=a[i]; a[i]:=a[j]; a[j]:=y;
y:=b[i]; b[i]:=b[j]; b[j]:=y; //每个人对应的三个数组都要跟着换
y:=c[i]; c[i]:=c[j]; c[j]:=y;
inc(i); dec(j);
end;
until (i>j);
ifl<j then qsort(l,j);
ifi<r then qsort(i,r);
end;
begin
readln(n);
readln(b[0],c[0]); //读入国王,国王不参与排序,所以‘0’
fori:=1 to n do //读入大臣,并计算左手*右手
begin
read(b[i],c[i]);
a[i]:=b[i]*c[i];
end;
qsort(1,n); //排序,原理见题解
l:=1;
g[1]:=b[0]; //从国王左手开始乘,赋初值
fori:=1 to n-1 do gj1; gj2; //最后一个得到的最多,所以由n-1个左手乘积/第n个右手乘积
fori:=l downto 1 do write(g[i]); //倒序输出
writeln;
end.
代码二:
var
i,j,k,m,n,x,y,len:longint;
s,sa,sb:ansistring;
a,ans,c:array[1..10000]of longint;
b:array[1..1010,1..3]of longint;
procedure qs(head,tail:longint);
var t,mid,i,j:longint;
begin
i:=head;j:=tail;mid:=b[(head+tail)>>1,3];
repeat
while b[i,3]
while b[j,3]>mid do dec(j);
if i<=j then
begin
t:=b[i,3];
b[i,3]:=b[j,3];
b[j,3]:=t;
t:=b[i,1];
b[i,1]:=b[j,1];
b[j,1]:=t;
t:=b[i,2];
b[i,2]:=b[j,2];
b[j,2]:=t;
inc(i);dec(j);
end;
until i>j;
if head
if i
end;
procedure cheng(x:longint);
var i,j,k:longint;
begin
for i:=1 to 10000 do
a[i]:=a[i]*x;
for i:=1 to 9999 do
begin
a[i+1]:=a[i+1]+a[i] div 10;
a[i]:=a[i] mod 10;
end;
end;
function bijiao:boolean;
var i,j:longint;
begin
for i:=10000 downto 1 do
begin
if ans[i]>c[i] then exit(false);
if c[i]>ans[i] then exit(true);
end;
exit(false);
end;
procedure dv(x:longint);
var i,d:longint;
begin
d:=0;
for i:=10000 downto 1 do
begin
d:=d*10+a[i];
c[i]:=d div x;
d:=d mod x;
end;
end;
begin
readln(n);
readln(x,y);a[1]:=x;
for i:=1 to n do
begin
readln(b[i,1],b[i,2]);
b[i,3]:=b[i,1]*b[i,2];
end;
qs(1,n);
len:=10000;
for i:=1 to n do
begin
dv(b[i,2]);
if bijiao then
for j:=len downto 1 do ans[j]:=c[j];
cheng(b[i,1]);
end;
len:=10000;
while (ans[len]=0)and(len<>1) do dec(len);
for i:=len downto 1 do write(ans[i]);
end.
NOIP2012 国王游戏 题解相关推荐
- NOIp2012D1T2 国王游戏 题解
国王游戏 洛谷P1080国王游戏 题解 这道题有个重要的性质:如果交换相邻两个大臣,获得金钱变化的有且只有这两个大臣.其余大臣得到的金钱不变. 我们考虑第 i i i个大臣和第 i + 1 i+1 i ...
- NOIP2012 国王游戏
2国王游戏 (game.cpp/c/pas) [问题描述] 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数 ...
- NOIP 提高组 2012 / 洛谷P1080 国王游戏 题解
题面: 略 简易题解: 假设第iii位大臣左手为LiL_{i}Li, 右手的数为R_{i} 并且我们有两位大臣iii,jjj,考虑他们的相对位置 (PPP 是 iii , jjj 之前的左手数值累乘 ...
- LiberOJ - 2603. 「NOIP2012」国王游戏
LiberOJ - 2603. 「NOIP2012」国王游戏 算法 (贪心) O ( n 2 ) O(n^2) O(n2) 我们先给出做法,再证明其正确性. 做法:直接将所有大臣按左右手上的数的乘积从 ...
- 【题解】P1080 国王游戏(贪心+高精python天下第一)
P1080 国王游戏 题目描述 恰逢 H国国庆,国王邀请n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排成一排 ...
- 国王游戏 [NOIP2012 提高组]
国王游戏 题目描述 恰逢 H 国国庆,国王邀请 n位大臣来玩一个有奖游戏. 首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n位大臣排成一排,国王站在 ...
- 做题记(4)P1080 国王游戏
今天,做了洛谷上的P1080 国王游戏,题目如下: 题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整 ...
- 【贪心】国王游戏(ybtoj 贪心-1-4)
国王游戏 ybtoj 贪心-1-4 题目大意 有一个国王和n个大臣 每人左右手分别有一个数,现在然你对大臣们排列(国王在第一个) 每个大臣所得金币是前面的人左手上的数的积除以他右手上的数 现在问你获得 ...
- # 国王游戏(贪心+大数乘除+微扰法证明)
国王游戏(贪心+大数乘除+微扰法证明) 题意:n个大臣和一个国王,左右手都有一个数,排队,国王始终拍在最前面,每个大臣的奖励为这个大臣前面的人的左手上的数之积除以这个大臣右手上的数.构造最优队伍,使得 ...
最新文章
- c++面向对象的编程
- C++重载>>和<<输入和输出运算符)
- clientdataset 遍历字段_TClientDataSet[5]: 读取数据
- Web框架之Django_04 模板层了解(过滤器、标签、自定义过滤器、标签、inclusion_tag、模板的继承与导入)
- Diango博客--20.开启 Django 博客的 RSS 功能
- linux遍历双向队列,双向循环队列
- 【转】【Asp.Net MVC】asp.net mvc Model验证总结及常用正则表达式
- exp/imp迁移表
- 简单使用linux感受,linux小白说说用linux的感受
- 【开学福利】13本python+AI书籍,快拿去
- 好IT男不能“淫”-谈IT人员目前普遍存在的“A情绪”
- 12个从小到超级成功的博客案例研究
- python unmatched_Python
- [Js] Js实现继承的5种方式
- 几款软件界面模型设计工具
- 基于微信小程序的游戏账号交易小程序
- excel用函数合并多个单元格内容,且用分隔符隔开
- window10新版本登录无限注销问题解决
- 4 种最安全的 MacBook 电池更换选项
- 安装完linux后要做的几件事。