luogu1080 國王遊戲(NOIP2012提高組第2題)
時空限制 1000ms/128MB
題目描述
恰逢 H 國國慶,國王邀請 n 位大臣來玩一個有獎遊戲。首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。然後,讓這 n 位大臣排成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然後向下取整得到的結果。
國王不希望某一個大臣獲得特別多的獎賞,所以他想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞儘可能的少。注意,國王的位置始終在隊伍的最前面。
輸入格式
第一行包含一個整數 n,表示大臣的人數。
第二行包含兩個整數 a 和 b,之間用一個空格隔開,分別表示國王左手和右手上的整數。
接下來 n 行,每行包含兩個整數 a 和 b,之間用一個空格隔開,分別表示每個大臣左手和右手上的整數。
輸出格式
一個整數,表示重新排列後的隊伍中獲獎賞最多的大臣所獲得的金幣數。
輸入輸出樣例
輸入 #1
3
1 1
2 3
7 4
4 6
輸出 #1
2
說明/提示
【輸入輸出樣例說明】
按 1 、2 、3 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 2;
按 1 、3 、2 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 2;
按 2 、1 、3 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 2;
按 2 、3 、1 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 9;
按 3 、1 、2 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 2;
按 3 、2 、1 這樣排列隊伍,獲得獎賞最多的大臣所獲得金幣數爲 9 。
因此,獎賞最多的大臣最少獲得 2 個金幣,答案輸出 2 。
【數據範圍】
對於 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。
NOIP 2012 提高組 第一天 第二題
代碼
法一:數組模擬
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005, M = 4010;
struct person{
int a,b;
bool operator < (const person &T)const{ return a*b<T.a*T.b; }
}p[N];
int n,c[M],d[M],ans[M]; //c累乘數組 d商數組 ans答案數組
void mul(int a[],int x){ //高*低
for (int i=1; i<=a[0]; i++) a[i]*=x;
for (int i=1; i<=a[0]; i++)
a[i+1]+=a[i]/10,a[i]%=10;
while (a[a[0]+1]){
a[0]++;
a[a[0]+1] += a[a[0]]/10;
a[a[0]] %= 10;
}
}
void div(int a[],int x,int b[]){ //高/低
fill(b,b+M,0);
b[0] = a[0];
for (int i=b[0],k=0; i>=1; i--){
k = k*10+a[i];
b[i] = k/x;
k %= x;
}
while (b[b[0]]==0 && b[0]>1) b[0]--;
}
bool isbig(int a[],int b[]){ //比較大小 返回a>b
if (a[0]!=b[0]) return a[0]>b[0];
for (int i=a[0]; i>=1; i--)
if (a[i]!=b[i]) return a[i]>b[i];
return false; //等時,返回false
}
void output(int a[]){
for (int i=a[0]; i>=1; i--) cout<<a[i];
cout<<endl;
}
int main(){
cin>>n;
for (int i=0; i<=n; i++) cin>>p[i].a>>p[i].b;
sort(p+1,p+n+1); //國王不參與排序
fill(c,c+M,0); c[0]=c[1]=1; //累乘數組,初始化爲1
fill(ans,ans+M,0); ans[0]=1;//答案數組,初始化爲0
for (int i=1; i<=n; i++){
mul(c,p[i-1].a); //前面的所有人的左手上的數的乘積 乘積存於c
div(c,p[i].b,d); //除以他自己右手上的數 商存於d
if (isbig(d,ans)) copy(d,d+M,ans); //打擂
}
output(ans);
return 0;
}
法二:重載運算符
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005, M = 4010;
struct person{
int a,b;
bool operator < (const person &T)const{ return a*b<T.a*T.b; }
}p[N];
struct bigint{
int s[M];
bigint(){ fill(s,s+M,0); s[0]=1; } //默認初始化全0
bigint(int x){ *this=x; } //int類型初始化
bigint operator = (int x){ //重載int賦值運算
fill(s,s+M,0);
do {
s[++s[0]] = x%10;
x /= 10;
} while (x);
return *this;
}
bigint operator * (const int &b){ //重載* 高*低
bigint c(*this);
for (int i=1; i<=c.s[0]; i++) c.s[i]*=b;
for (int i=1; i<=c.s[0]; i++)
c.s[i+1]+=c.s[i]/10, c.s[i]%=10;
while (c.s[c.s[0]+1]){
c.s[0]++;
c.s[c.s[0]+1] += c.s[c.s[0]]/10;
c.s[c.s[0]] %= 10;
}
c.clear0();
return c;
}
bigint operator / (const int &b){ //重載/ 高/低
bigint c(*this);
int x=0;
for (int i=c.s[0]; i>=1; i--){
x = 10*x+c.s[i];
c.s[i] = x/b;
x %= b;
}
c.clear0();
return c;
}
void clear0(){ //清掉高位0,保證數據至少1位
while (s[s[0]]==0&&s[0]>1) s[0]--;
}
bigint operator *= (const int &b){ *this=*this*b; return *this; } //重載*=
bool operator < (const bigint &b)const{ //重載<
if (s[0]!=b.s[0]) return s[0]<b.s[0];
for (int i=s[0]; i>=1; i--)
if (s[i]!=b.s[i]) return s[i]<b.s[i];
return true;
}
};
ostream& operator << (ostream &out,const bigint &x){//重載輸出流
for (int i=x.s[0]; i>=1; i--) out<<x.s[i];
return out;
}
int main(){
int n;
cin>>n;
for (int i=0; i<=n; i++) cin>>p[i].a>>p[i].b;
sort(p+1,p+n+1); //國王不參與排序
bigint x=1,y,ans=0; /*需重載 int賦值*/
for (int i=1; i<=n; i++){
x *= p[i-1].a; /*需重載高*低、高*=低*/
y = x/p[i].b; /*需重載高/低*/
if (ans<y) ans=y; /*需重載 < */
}
cout<<ans<<endl; /*需重載輸出流*/
return 0;
}