$Luogu P1080$ 国王游戏
作者:互联网
背景
题意
给定国王和 \(n\) 个大臣左右手上的数 \(a\) 和 \(b\) 。每个大臣 \(i\) 获得金币为 \(国王左手金币数 \times \frac{\prod_{j=1}^{i-1} a[j]}{b[i]}\) ,请设计一个排队顺序使得到金币数最多的大臣获得的金币数最小,注意国王只能在队首。
解法
咕咕咕
\(trick\)
以排序为贪心策略的题目大概率是用微扰法(邻项交换法)证明的。最终结果的序列一定不能通过交换使得答案变大。
细节
1.每个大臣进队时,乘入结果的是上一个大臣左手上的数,除以的是自己手上的数。
2.此题只有 \(60\%\) 的数据答案在 \(10^9\) 以内,其余的均要使用高精度解决。高精度模板
代码
\(View\) \(Code\)
#include<bits/stdc++.h>
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<y.a*y.b;
}
inline void mul(int x)
{
int tmp=0;
for(register int i=1;i<=lens;i++)
sum[i]*=x;
for(register int i=1;i<=lens;i++)
{
tmp+=sum[i];
sum[i]=tmp%10;
tmp/=10;
}
while(tmp)
{
lens++;
sum[lens]=tmp%10;
tmp/=10;
}
}
inline void div(int x)
{
memset(ans,0,sizeof(ans));
lena=lens;
int tmp=0;
for(register int i=lena;i;i--)
{
tmp*=10;
tmp+=sum[i];
if(tmp>=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]<ans[i])
{
for(register int j=1;j<=lena;j++)
maxn[j]=ans[j];
lenm=lena;
break;
}
}
}
}
inline void write()
{
for(register int i=lenm;i;i--)
printf("%d",maxn[i]);
}
int main()
{
n=read();
s[0].a=read();
s[0].b=read();
for(register int i=1;i<=n;i++)
{
s[i].a=read();
s[i].b=read();
}
sort(s+1,s+n+1,cmp);
for(register int i=1;i<=n;i++)
{
mul(s[i-1].a);
div(s[i].b);
cmp1();
}
write();
return 0;
}
标签:lena,ch,游戏,int,Luogu,金币,大臣,P1080,国王 来源: https://www.cnblogs.com/Peter0701/p/11237138.html