1. 程式人生 > >NOIP2012【國王遊戲】

NOIP2012【國王遊戲】

【題解】

  一開始看著題覺得是二分答案(最大值的最小值),後來發現不滿足單調性

  再後來發現可以用貪心做:只需把大臣按照左手*右手升序排序即可

  證明:

   很顯然前面的大臣位置隨便調換對後面的大臣並沒有影響

  那麼假設現在已經排了i-1個大臣,p=a[1]*a[2]*a[3]*……*a[i-1];

  第i個大臣的錢w[i]=p/b[i],第i+1個大臣的錢w[i+1]=p*a[i]/b[i+1]

  若i+1大臣在i大臣前面

  第i個大臣的錢w[i]=p*a[i+1]/b[i],第i+1個大臣的錢w[i+1]=p/b[i+1]

  顯然p*a[i+1]/b[i]>p/b[i]  &&  p*a[i]/b[i+1]>p/b[i+1]

  所以兩個裡面的最大值在p*a[i+1]/b[i] 和 p*a[i]/b[i+1] 之間  

  若p*a[i+1]/b[i] > p*a[i]/b[i+1](這樣就是i+1大臣排在i後面最大值會更小) 則 a[i+1]*b[i+1]>a[i]*b[i]

  所以如果要讓大臣得到的錢的最大值最小就要保證兩個相鄰的大臣,前面的左手*右手<後面的左手*右手

  (一年前打的題目,現在寫題解還要寫好久,果然我還是太菜了)

   詳見程式碼(記得打高精度,還有interesting的高精除法噢233)

#include <algorithm> 
#include <iostream>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cstring>
#include <string>
using namespace std;

struct info
  {
    int l,r,k;
  }num[1001];
  
inline bool cmp(const info &a,const info &b)
  {
	return a.k<b.k;
  }
int f[20000];
int i,j,k,l,m,n,t;

int main()
  {
    scanf("%d",&n);
    for(i=0;i<=n;i++)
	  {
        scanf("%d%d",&num[i].l,&num[i].r);
        num[i].k=num[i].r*num[i].l;
      }
    sort(num+1,num+n+1,cmp);
    f[1]=num[0].l;f[0]=1;
    for (int i=1;i<=n-1;i++)
	  {
	   t=0;
    	for (int j=1;j<=f[0];j++)
		  {
    		f[j]*=num[i].l;f[j]+=t; 
			t=f[j]/10000;f[j]%=10000;
    	  }
    	if (t>0) f[++f[0]]=t; 
      }
    t=0;
    for (int i=f[0];i>=1;i--)
	  {
    	t+=f[i];f[i]=t/num[n].r;
    	t%=num[n].r;
    	t*=10000;
      }  
    for (;f[f[0]]==0 && f[0]>0;f[0]--);
    if (f[f[0]]==0) printf("1");else printf("%d",f[f[0]]);
    for (int i=f[0]-1;i>=1;i--)
	  {
    	if (f[i]<10) printf("000");
    	if (f[i]<100 && f[i]>=10) printf("00");
    	if (f[i]<1000 && f[i]>=100) printf("0");
		printf("%d",f[i]);
      }
}