【luogu1080】国王游戏(高精度)

题目:

我是超链接

题解:

首先证明一些东西

可知相邻的两个交换位置,只对这两个有影响。我们设i和j,使j站在i的后面金币数保持最小。令i前面所有人左手乘积为Q,对于j而言,想要使得j的金钱尽量小,必须满足Q*ai/bj<Q*aj/bi  然后化简,两边消掉Q,同时乘以bj和bi  可知此时ai*bi<aj*bj

那我们先按照这个东西排序,那么这是所有排列中最小的一种。

然后要做的就是看看这种排列中,大臣们拿的最多的金币是多少,需要运用高精度!!!因为a和b的范围,我们就压5位.

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct hh{int a,b,c;}c[1005];
int sum[2000],divv[2000],ans[2000];
int cmp(hh a,hh b){return a.c<b.c;}
bool compare()
{
	bool fff=false;
	if (divv[0]>ans[0]) return 1;
	for (int i=divv[0];i>0;i--)
	  if (divv[i]>ans[i]) return 1;
	return 0;
}
int main()
{
	int n,i,j;
	scanf("%d",&n);
	for (i=0;i<=n;i++)
	  scanf("%d%d",&c[i].a,&c[i].b),c[i].c=c[i].a*c[i].b;
	sort(c+1,c+n+1,cmp);
	sum[0]=1; sum[1]=1;
    for (i=1;i<=n;i++)
    {
    	int x=0;
    	for (j=1;j<=sum[0];j++)
    	{
    		sum[j]=sum[j]*c[i-1].a+x;
    		x=sum[j]/100000;
    		sum[j]%=100000;
		}
    	if (x>0){sum[0]++; sum[sum[0]]=x;}
    	x=0;
    	memset(divv,0,sizeof(divv));
    	for (j=sum[0];j>0;j--)
    	{
    		divv[j]=(x*100000+sum[j])/c[i].b;
    		x=(x*100000+sum[j])%c[i].b;
		}
		divv[0]=sum[0];
		while (divv[divv[0]]==0) divv[0]--;
		
		if (compare()) for (j=0;j<=divv[0];j++) ans[j]=divv[j];
	}
	printf("%d",ans[ans[0]]);
	for (i=ans[0]-1;i>0;i--)
	{
		printf("%d",ans[i]/10000);
		printf("%d",ans[i]/1000%10);
		printf("%d",ans[i]/100%10);
		printf("%d",ans[i]/10%10);
		printf("%d",ans[i]%10);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值