zoukankan      html  css  js  c++  java
  • CF792E Colored Balls【思维】

    题目传送门

    考试的时候又想到了小凯的疑惑,真是中毒不浅...

    设每一个数都可以被分成若干个$k$和$k+1$的和。数$x$能够被分成若干个$k$和$k+1$的和的充要条件是:
    $x%k<=floor(x/k)$

    又因为$k$一定小于这个数列中最小的那个数,可以轻易想到的一个朴素的方法就是从$1$到$A_{min}$枚举所有可能的$k$,判断是否满足情况,并更新答案。

    注意到$k$越大,答案越优,所以从大到小进行枚举,找到答案就退出。

    我们现在来优化他:

    可以想到,当$k<=sqrt{x}$,上述不等式一定成立。

    所以只需要判断$k$在$(sqrt{x},x]$范围内是否满足就可以了。

    可是$x$在$1e9$的范围内,还是会超时呢。

    其实我们枚举到了很多无用的$k$,因为要保证$A_{min}$也可以分成若干个$k$和$k+1$的和,所以实际上有效的$k$是:$A_{min}$,$A_{min}/2$,$A_{min}/3$...诸如此类的数...

    我们可以枚举集合个数($A_{min}$可以被拆成多少个数),然后通过集合个数来算$k$

    枚举范围就从$(sqrt{x},x]$变成了$(1,sqrt{x}]$

    在代码里,我特判了一下$1$的情况(其实是因为考试稳妥)

    还有一些细节问题都放在注释里了

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<queue>
     5 #include<cmath>
     6 using namespace std;
     7 #define N 505
     8 #define ll long long
     9 int n;
    10 int a[N];
    11 ll ans;
    12 int rd()
    13 {
    14     int f=1,x=0;char c=getchar();
    15     while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    16     while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    17     return f*x;
    18 }
    19 int res=-1;
    20 bool check(int k,int ret,int id)
    21 {//如果余数为0 有一次将k调整成k-1的机会 
    22     for(int i=1;i<=n;i++)
    23     {
    24         int p=a[i]/k,q=a[i]%k;
    25         if(ret&&q>p) return 0;
    26         if(!ret)
    27         {
    28             if(q>p)
    29             {
    30                 k--;
    31                 ret=1;
    32                 p=a[i]/k,q=a[i]%k;
    33             }
    34             if(q>p) return 0;
    35         }
    36     }
    37     res=k;
    38     return 1;
    39 }
    40 int main()
    41 {
    42     n=rd();
    43     for(int i=1;i<=n;i++)
    44         a[i]=rd();
    45     sort(a+1,a+n+1);
    46     if(a[1]==1)
    47     {
    48         for(int i=2;i<=n;i++)
    49         {
    50             if(a[i]&1)
    51             {
    52                 ans+=(a[i]-1)>>1;
    53                 ans++;
    54             }
    55             else ans+=(a[i]>>1);
    56         }
    57         printf("%lld
    ",ans+1);
    58         return 0;
    59     }
    60     for(int i=1;i<=int(sqrt(a[1]))+1;i++)
    61     {//枚举集合个数 (对于最小的数) 
    62         int k=a[1]/i;//集合大小 k和k+1
    63         int ret=a[1]%i;//如果是整除 就不能确定是k-1和k 还是k和k+1
    64         //如果有余数 肯定是k和k+1(k还不够) 
    65         //如果余数为0 有一次将k调整成k-1的机会 
    66         if(check(k,ret,i))
    67             break;
    68     }
    69     //printf("%d
    ",res);
    70     for(int i=1;i<=n;i++)
    71         ans+=(a[i]+res)/(res+1);
    72     printf("%lld
    ",ans);
    73     return 0;
    74 }
    75 /*
    76 2
    77 948507270 461613425
    78 */
    Code
  • 相关阅读:
    How to install VXDIAG Honda, Toyota and JLR SDD software
    16% off MPPS V16 ECU tuning tool for EDC15 EDC16 EDC17
    Cummins INSITE locked and ask for verification code
    How to use BMW Multi Tool 7.3 to replace lost key for BMW X1
    Bleed Brake Master Cylinder with Intelligent Tester IT2
    Porsche Piwis Tester II “No VCI has been detected”,how to do?
    Creader VIII VS. Creader VII+
    How to solve GM MDI cannot complete the installation
    汽车OBD2诊断程序开发 (原文转载,思路很清晰!)
    汽车节温器单片机开发思路
  • 原文地址:https://www.cnblogs.com/lyttt/p/11853345.html
Copyright © 2011-2022 走看看