关于高精度算法的小理解大家可以看看我的文章嘿嘿嘿 浅谈高精度算法
一.题目描述
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入
第一行包含一个整数 n,表示大臣的人数。 第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。 接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手 和右手上的整数。
输出
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的 金币数
样例输入 Copy
3
1 1
2 3
7 4
4 6
样例输出 Copy
2
二.思路(这个思路据说经常有用所以就写的细一点啦!!)
- 按照每个大臣左、右手上的数的乘积从小到大排序,就是最优排队方案。
- 对于任意一种顺序,设n名大臣左、右手上的数分别是a[1]–a[n],与b[1]–b[n],国王手里的数是a[0]和b[0]。
- 比如说下图最简单的一种队伍:
- 这张图来自于别人的分析哈~由于我实在不会打出那样的分数嘿嘿嘿。这个图里的字母应该都是数组里放着的数哈!
- 这两种情况就是交换了两个大臣之后各自得到的最大的奖励。其他大臣得到的奖励显然不变。只需要比较上面两组式子中最大值的变化情况。
- 将两个max里的数同时乘上b[ i ]*b[i+1],变为比较:max(a[0]*b[2],a[0]*a[1]*b[1]) 和 max(a[0]*b[1],a[0]*a[2]*b[2])。去掉公因子,比较max(b[2],a[1]*b[1])和max(b[1],a[2]*b[2])。
- 由于大臣手里的数字都是正整数,故b[2]<=a[2]*b[2],且a[1]*b[1]>=b[1].
- 于是,当a[1]*b[1]<=a[2]*b[2]时,上式<=下式,交换前更优,反之,上式>=下式,交换后更优。也就是说,在任何情况下,减小或增加逆序对数都不会使整体结果达到最优,当运用冒泡排序使其变为有序序列——逆序对数为0时,达到最优。
- 以上是最简单情况的推导,大家可以用 i 来进行更一般结论的推导,结论是一样的哈!
不要忘记高精度算法的使用哦!!!否则oj过不去啊数据太大了要命啊~
#include <bits/stdc++.h>
using namespace std;
int A[10001],B[10001],D[10001];
struct node{
int a;//左
int b;//右
long long ji;//记录a*b
}q[1001];
int read()
{
int a1=0,sign=1;
char c=getchar();
while((c<'0'||c>'9')&&c!='-') c=getchar();
if(c=='-')
{
sign=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
a1=a1*10+c-'0';//转化为一个完整的多位数
c=getchar();
}
return a1*sign;
}
bool cmp(node a1,node b1)
{
return a1.ji<b1.ji;//从小到大排序的意思
}
void chengfa(int a1)
{
memset(B,0,sizeof(B));
for(int i=1;i<=A[0];i++)
{
A[i]*=a1;//实现与前面人的相乘
B[i+1]+=A[i]/10;//相当于去掉个位
A[i]%=10;//存个位数
}
for(int i=1;i<=A[0]+4;i++)
{
A[i]+=B[i];//确定每一位上最终的数
if(A[i]>=10)
{
A[i+1]+=A[i]/10;//进位
A[i]%=10;//确定每一位的数字
}
if(A[i]!=0)//条件可避免位数多了
{
A[0]=max(A[0],i);//确定位数
}
}
return;
}
int chufa(int b1)
{
memset(B,0,sizeof(B));
int e=0;
for(int i=A[0];i>=1;i--)
{
e*=10;
e+=A[i];
B[i]=e/b1;//从高位开始除法
if(B[0]==0&&B[i]!=0)//条件是这个的原因是,i从高位开始减的哦!
{
B[0]=i;//确定位数
}
e%=b1;//确定余数
}
}
bool bijiao()
{
if(D[0]==B[0])
{
for(int i=B[0];i>=1;i--)
{
if(B[i]>D[i])
return 1;
if(B[i]<D[i])
return 0;
}
}
if(B[0]>D[0])
return 1;
if(B[0]<D[0])
return 0;
}
void fuzhi()
{
memset(D,0,sizeof(D));
for(int i=B[0];i>=0;i--)
{
D[i]=B[i];
}
return;
}
int main()
{
int n=read();
for(int i=0;i<=n;i++)
{
q[i].a=read();
q[i].b=read();
q[i].ji=q[i].a*q[i].b;
}
sort(q+1,q+1+n,cmp);//从小到大排序
A[0]=1;
A[1]=1;
for(int i=1;i<=n;i++)
{
chengfa(q[i-1].a);
chufa(q[i].b);
if(bijiao())
fuzhi();
}
for(int i=D[0];i>=1;i--)
{
printf("%d",D[i]);
}
return 0;
}