NOIP 提高组 2012 / 洛谷P1080 国王游戏 题解

题面:

简易题解:

假设第 i i i位大臣左手为 L i L_{i} Li, 右手的数为R_{i}
并且我们有两位大臣 i i i j j j,考虑他们的相对位置

( P P P i i i , j j j 之前的左手数值累乘)

某一个时候, 假设 i i i j j j 前一个位置,则此时:
j j j 号大臣能获得的金币为 P × L i R j \frac{P \times L_{i} } {R_{j}} RjP×Li
i i i 号大臣能获得的金币为 P R i \frac{P}{R_{i}} RiP
所以这两个的最大值为 m a x ( P × L i R j , P R i ) max( \frac{P \times L_{i}} {R_{j}}, \frac{P}{R_{i}} ) max(RjP×Li,RiP)

i i i j j j交换位置,则此时:
i i i号大臣能获得的金币为 P × L j R i \frac{P \times L_{j}} {R_{i}} RiP×Lj
j j j号大臣能获得的金币为 P R j \frac{P}{R_{j}} RjP
所以这两个的最大值为 m a x ( P × L j R i , P R j ) max( \frac{P \times L_{j}} {R_{i}}, \frac{P}{R_{j}} ) max(RiP×Lj,RjP)

我们来比较一下这两个的最大值:
倘若第一种情况更优,则:
m a x ( P × L j R i , P R j ) > m a x ( P × L i R j , P R i ) max( \frac{P \times L_{j}} {R_{i}}, \frac{P}{R_{j}} ) > max( \frac{P \times L_{i}} {R_{j}}, \frac{P}{R_{i}} ) max(RiP×Lj,RjP)>max(RjP×Li,RiP)

同时约去 P P P,得:
m a x ( L j R i , 1 R j ) > m a x ( L i R j , 1 R i ) max( \frac{L_{j}} {R_{i}}, \frac{1}{R_{j}} ) > max( \frac{ L_{i}} {R_{j}}, \frac{1}{R_{i}} ) max(RiLj,Rj1)>max(RjLi,Ri1)

由于
1 R j < L i R j \frac{1}{R_{j}} < \frac{ L_{i}} {R_{j}} Rj1<RjLi

1 R i < L j R i \frac{1}{R_{i}} < \frac{ L_{j}} {R_{i}} Ri1<RiLj

则我们只需要满足

L i R j < L j R i \frac{L{i}}{R_{j}} < \frac{ L_{j}} {R_{i}} RjLi<RiLj

L i × R i < L j × R j L_{i} \times R_{i} < L_{j} \times R_{j} Li×Ri<Lj×Rj

也就是说,当 L × R L \times R L×R 小的在前面时,总的答案就会更优

然后就是喜闻乐见的高精度了

Code

#include
using namespace std;
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
const int N=1e4+4;
struct Man{
	int l,r;
	bool operator<(const Man &rhs)const{
		return l*r<rhs.l*rhs.r;
	}
}m[N];
int a,b,n;
struct Int{
	int a[10004];//a[0] 表示位数
	Int operator*(int b)const{
		Int tmp; tmp.a[0]=0;
		int t=log(b)/log(10); 
		rep(i,1,t+a[0]+2) tmp.a[i]=0;
		rep(i,1,a[0]){
			int tt=a[i]*b;
//			cout<
int t0=0;
			while(tt){
				tmp.a[i+t0]+=tt%10;
				tt/=10; t0++;
			}
		}
		repd(i,t+a[0]+1,0) if(tmp.a[i]>0){
			tmp.a[0]=i; break;
		}
		return tmp;
	} 
	Int operator/(int b)const{
		Int tmp; tmp.a[0]=0;
		rep(i,1,a[0]) tmp.a[i]=0;
		if(a[0]==0) return *this;
		int tt=0,p=0;bool fl=0;
		repd(i,a[0],1){
			tt=tt*10+a[i];
			if(tt>=b){
				if(!fl) tmp.a[0]=i;
				fl=1;
				tmp.a[i]=tt/b;
				p=tt%b;
				tt=p;
			}
		}
		return tmp;
	}
	bool operator<(Int b)const{
		if(a[0]<b.a[0]) return true;
		else if(a[0]>b.a[0]) return false;
		else repd(i,a[0],1){
				if(a[i]<b.a[i]) return true;
				else if(a[i]>b.a[i]) return false;
			}
	}
}ans,s;
int main(){
	g(n);
	g(m[0].l),g(m[0].r);
	rep(i,1,n) g(m[i].l), g(m[i].r);
	sort(m+1,m+1+n);
	ans.a[1]=1;ans.a[0]=1; s.a[1]=s.a[0]=1;
	rep(i,1,n){
		if(ans<s/m[i].r) ans=s/m[i].r,ans.a[0]--;
		s=s*m[i].l;
	}
	repd(i,ans.a[0],1) printf("%d",ans.a[i]);
	return 0;
}

你可能感兴趣的:(水题挑战,贪心,贪心,算法)