NOIP2012【國王遊戲】
阿新 • • 發佈:2019-01-02
【題解】
一開始看著題覺得是二分答案(最大值的最小值),後來發現不滿足單調性
再後來發現可以用貪心做:只需把大臣按照左手*右手升序排序即可
證明:
很顯然前面的大臣位置隨便調換對後面的大臣並沒有影響
那麼假設現在已經排了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]); } }