参考链接:http://www.cnblogs.com/barrier/p/6647594.html
题目链接:http://codeforces.com/contest/792/problem/E
题目大意是将各种颜色的球分组,要求每组只能有一种颜色并且任一两组球个数之差不能大于一。
枚举+贪心
刚开始看觉得需要判断x-1,x与x,x+1两种情况,但是实际上x-1,x可以包括在x,x+1的情况中
引用参考链接中的:
设每个盒子中可以存放x或x+1个球,则任意颜色的球的个数都可以表示为ux+v(x+1).
故可任选一种颜色的球a,枚举p,令k=a/p,r=a%p,即a=kp+r.
根据r的值,可分为两种情况:
- r≠0时,x仅有两种可能,x=k或x=p.
- r=0时,x有四种可能,x=k或x=p或x=k−1或x=p−1.
将上面得到的x带入各个颜色检验,由于要求最少盒子,故优先以x+1x+1为单位将球分组:ai=k(x+1)+r.
如果ai%(x+1)!=0的话,则ai%x<=ai/x
p实际上只用枚举到sqrt(ai)即可,否则可能超时
注意结果可能为多个10e9相加,因此要long long.
代码:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<cstdio>
3 #include<iostream>
4 #include<cstdlib>
5 #include<algorithm>
6 #include<cmath>
7 #include<vector>
8 #include<string>
9 #include<map>
10 using namespace std;
11
12 const int maxn = 505;
13 const long long inf = 0x3f3f3f3f3f3f3f3f;
14 int n;
15 int a[maxn];
16
17 long long check(int p)
18 {
19 long long res = 0;
20 for (int i = 0; i < n; i++)
21 {
22 if (a[i] % (p + 1) != 0 && a[i] % (p) > a[i] / p) return inf;
23 res += a[i] / (p + 1) + (a[i] % (p + 1) == 0 ? 0 : 1);
24 }
25 return res;
26 }
27
28 int main()
29 {
30 cin >> n;
31 for (int i = 0; i < n; i++)
32 {
33 scanf("%d", &a[i]);
34 }
35 long long res = inf, k = 0, b = a[0];
36 for (int i = 0; i < n; i++)
37 if (b > a[i]) b = a[i];
38 for (k = 1; k*k <= b; k++)
39 {
40 int p = b / k;
41 res = min(res, check(k));
42 res = min(res, check(p));
43 int r = b%k;
44 if (r == 0)
45 {
46 res = min(res, check(k - 1));
47 res = min(res, check(p - 1));
48 }
49 }
50 cout << res << endl;
51 return 0;
52 }