码迷,mamicode.com
首页 > 其他好文 > 详细

CF792E Colored Balls【思维】

时间:2019-11-13 22:23:08      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:pre   lld   不等式   force   一个   namespace   click   技术   tar   

题目传送门

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

设每一个数都可以被分成若干个$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\n",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\n",res);
70     for(int i=1;i<=n;i++)
71         ans+=(a[i]+res)/(res+1);
72     printf("%lld\n",ans);
73     return 0;
74 }
75 /*
76 2
77 948507270 461613425
78 */
Code

 

CF792E Colored Balls【思维】

标签:pre   lld   不等式   force   一个   namespace   click   技术   tar   

原文地址:https://www.cnblogs.com/lyttt/p/11853345.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!