[NOIP2012]国王游戏 题解
Posted SHYI
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2012]国王游戏 题解相关的知识,希望对你有一定的参考价值。
题目大意:
n个人排成一排,排头固定,其他可以变。每一个人左右手都有一个整数,一个人的分数为他所有前面的人左手上的数的乘积除以他右手上的数(向下取整),求在整列中最大分数的最小值。
思路:
首先,一切序列都可以通过若干次相邻的人的交换实现转换,而相邻的人的交换只会影响这两个人的分数。
假设相邻的两人为i,i+1,则令a[i]*b[i]<=a[i+1]*b[i+1],设i之前的和为S,则交换前的ans1=max{S/b[i],S*a[i]/b[i+1]},交换后ans2=max{S/b[i+1],S*a[i+1]/b[i]}。∵a[i],a[i+1],b[i],b[i+1],S均为正整数,∴S*a[i]>=S,∴S*a[i]/b[i+1]>=S/b[i+1]。
同理:S*a[i+1]/b[i]>=S/b[i]。
又∵a[i]*b[i]<=a[i+1]*b[i+1]且a[i],a[i+1],b[i],b[i+1],S均为正整数,∴S*a[i]*b[i]<=S*a[i+1]*b[i+1],∴S*a[i]/b[i+1]<=S*a[i+1]/b[i],∴ans2>=ans1,∴要使最终ans最小则要使每个人左右手的数的乘积从小到大排列,在计算答案。
由于数据较大,需要用到高精度(压位),乘法没什么问题,除法注意边界条件!
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int M=10005,N=100000; 6 int n,i,l,p,len,a[M],b[M],c[M],s[M],d[M],z[M],id[M],ans[M]; 7 8 bool cmp(int x,int y) { return s[x]<s[y]; } 9 10 void cheng(int x) 11 { 12 int i,t=0; 13 for (i=1;i<=len;++i) 14 { 15 c[i]=t+c[i]*x; 16 t=c[i]/N; 17 c[i]=c[i]%N; 18 } 19 if (t) c[++len]=t; 20 } 21 22 bool pd() 23 { 24 if (l>p) return 1; 25 for (int i=1;i<=l;i++) 26 if (ans[i]<d[i]) return 1; 27 return 0; 28 } 29 30 void chu(int y) 31 { 32 int i=len,t,x=z[len]; 33 for (l=0;i;) 34 { 35 if (i>1) { if (x<y) x=x*N+z[--i]; } else break; 36 d[++l]=x/y;x=x%y; 37 } 38 if (x>=y) d[++l]=x/y; 39 if (pd()) for (p=l,i=1;i<=l;i++) ans[i]=d[i]; 40 } 41 42 int main() 43 { 44 scanf("%d%d%d",&n,&a[0],&b[0]); 45 for (i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),s[i]=a[i]*b[i],id[i]=i; 46 sort(id+1,id+1+n,cmp); c[len=1]=a[0]; 47 for (i=1;i<=n;i++) memcpy(z,c,sizeof c),chu(b[id[i]]),cheng(a[id[i]]); 48 printf("%d",ans[1]); 49 for (i=2;i<=p;i++)//printf("%05d",ans[i]); 50 if (ans[i]>10000) printf("%d",ans[i]); 51 else if (ans[i]>1000) printf("0%d",ans[i]); 52 else if (ans[i]>100) printf("00%d",ans[i]); 53 else if (ans[i]>10) printf("000%d",ans[i]); 54 else printf("0000%d",ans[i]); 55 return 0; 56 }
以上是关于[NOIP2012]国王游戏 题解的主要内容,如果未能解决你的问题,请参考以下文章