前言:听高一的说今晚JT会过来讨论停课集训的事情。啊啊啊好想停课啊,不想上文化课QAQ……
题目传送门:https://www.luogu.org/problem/show?pid=1080
题目分析:刷一下前几年的NOIP真题……
这题有一个结论:将每个大臣按左手上的数乘以右手上的数从小到大排序,即是最优的排列方法。为了证明这个贪心,不妨只考虑当前相邻的两个大臣
i,j
,看一下他们交换位置后是否使答案更优(很明显他们交换不会影响前后的大臣的金币数)。假设他们左右手上的数分别为
ai,bi,aj,bj
,前面的人左手上的数乘积为sum。如果
i
在
我不会告诉你我一开始看成了答案等于所有大臣金币数之和,然后推出了另外一条式子,码code的时候还因此写了个高进度加法……
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
const int maxm=1000000;
struct data
{
int a,b;
} p[maxn];
int t[maxm];
int d[maxm];
int ans[maxm];
int n;
bool Comp(data x,data y)
{
return x.a*x.b<y.a*y.b;
}
void Times(int *X,int v,int *Y)
{
int len=X[0];
for (int i=1; i<=len+20; i++) Y[i]=0;
for (int i=1; i<=len; i++)
{
Y[i]+=(X[i]*v);
Y[i+1]+=(Y[i]/10);
Y[i]%=10;
}
while (Y[len+1]>0)
{
len++;
Y[len+1]+=(Y[len]/10);
Y[len]%=10;
}
Y[0]=len;
}
void Div(int *X,int v,int *Y)
{
int len=X[0];
int rest=0;
for (int i=len; i>=1; i--)
{
rest=rest*10+X[i];
Y[i]=rest/v;
rest-=(v*Y[i]);
}
while (!Y[len]) len--;
if (!len) len=1;
Y[0]=len;
}
void Get_max(int *X,int *Y)
{
if (Y[0]<X[0]) return;
if (Y[0]==X[0])
for (int i=Y[0]; i>=1; i--)
if (Y[i]<X[i]) return;
else if (Y[i]>X[i]) break;
for (int i=0; i<=Y[0]; i++) X[i]=Y[i];
}
int main()
{
freopen("1080.in","r",stdin);
freopen("1080.out","w",stdout);
scanf("%d",&n);
for (int i=0; i<=n; i++) scanf("%d%d",&p[i].a,&p[i].b);
sort(p+1,p+n+1,Comp);
t[0]=1;
t[1]=1;
for (int i=1; i<=n; i++)
{
Times(t,p[i-1].a,d);
for (int j=0; j<=d[0]; j++) t[j]=d[j];
Div(t,p[i].b,d);
Get_max(ans,d);
}
for (int i=ans[0]; i>=1; i--) printf("%d",ans[i]);
printf("\n");
return 0;
}