zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    机器学习踩坑之Win10+Ubuntu双系统安装踩坑经验
    面向对象
    模块(三)
    模块(二)
    模块之日志
    包的基础使用
    模块介绍
    递归
    匿名函数与三元表达式
    生成器与迭代器
  • 原文地址:https://www.cnblogs.com/HHshy/p/6035852.html
Copyright © 2011-2022 走看看