Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力(
Posted 阿波罗2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力(相关的知识,希望对你有一定的参考价值。
题目传送门
题目大意
求一个满足$d\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d} \\right \\rceil - \\sum_{i = 1}^{n} a_{i} \\leqslant K$的最大正整数$d$。
整理一下可以得到条件是$d\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d} \\right \\rceil \\leqslant K + \\sum_{i = 1}^{n} a_{i}$
有注意到$\\left \\lceil \\frac{a_i}{d} \\right \\rceil$的取值个数不会超过$2\\left \\lceil \\sqrt{a_i} \\right \\rceil$。
证明考虑对于$1 \\leqslant d \\leqslant \\left \\lceil \\sqrt{a_i} \\right \\rceil$,至多根号种取值,当$d >\\left \\lceil \\sqrt{a_i} \\right \\rceil$的时候,取值至多为$1, 2, \\cdots, \\left \\lceil \\sqrt{a_i} \\right \\rceil$,所以总共不会超过$2\\left \\lceil \\sqrt{a_i} \\right \\rceil$个取值。
所以我们把所有$\\left \\lceil \\frac{a_i}{d} \\right \\rceil$的取值当成一个点,安插在数轴上,排个序,就愉快地找到了所有分段了。因为每一段内的$d$都是等价的,所以只需要用每一段的左端点计算和,然后判断$\\left \\lfloor \\frac{K + \\sum_{i = 1}^{n} a_{i}}{\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d} \\right \\rceil} \\right \\rfloor$是否在区间内,如果是就用它去更新答案。
Code
1 /** 2 * Codeforces 3 * Problem#831F 4 * Accepted 5 * Time:997ms 6 * Memory:100400k 7 */ 8 #include <iostream> 9 #include <cstdio> 10 #include <ctime> 11 #include <cmath> 12 #include <cctype> 13 #include <cstring> 14 #include <cstdlib> 15 #include <fstream> 16 #include <sstream> 17 #include <algorithm> 18 #include <map> 19 #include <set> 20 #include <stack> 21 #include <queue> 22 #include <vector> 23 #include <stack> 24 #ifndef WIN32 25 #define Auto "%lld" 26 #else 27 #define Auto "%I64d" 28 #endif 29 using namespace std; 30 typedef bool boolean; 31 const signed int inf = (signed)((1u << 31) - 1); 32 const signed long long llf = (signed long long)((1ull << 63) - 1); 33 const double eps = 1e-6; 34 const int binary_limit = 128; 35 #define smin(a, b) a = min(a, b) 36 #define smax(a, b) a = max(a, b) 37 #define max3(a, b, c) max(a, max(b, c)) 38 #define min3(a, b, c) min(a, min(b, c)) 39 template<typename T> 40 inline boolean readInteger(T& u){ 41 char x; 42 int aFlag = 1; 43 while(!isdigit((x = getchar())) && x != \'-\' && x != -1); 44 if(x == -1) { 45 ungetc(x, stdin); 46 return false; 47 } 48 if(x == \'-\'){ 49 x = getchar(); 50 aFlag = -1; 51 } 52 for(u = x - \'0\'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - \'0\'); 53 ungetc(x, stdin); 54 u *= aFlag; 55 return true; 56 } 57 58 #define LL long long 59 60 int n; 61 LL C; 62 int* a; 63 vector<LL> seg; 64 65 template<typename T> 66 T ceil(T a, T b) { 67 return (a + b - 1) / b; 68 } 69 70 inline void init() { 71 readInteger(n); 72 readInteger(C); 73 seg.push_back(1); 74 a = new int[(n + 1)]; 75 for(int i = 1, x; i <= n; i++) { 76 readInteger(a[i]); 77 for(int j = 1; j * j <= a[i]; j++) 78 seg.push_back(j), seg.push_back(ceil(a[i], j)); 79 C += a[i]; 80 } 81 seg.push_back(llf); 82 } 83 84 LL res = 1; 85 inline void solve() { 86 sort(seg.begin(), seg.end()); 87 int m = unique(seg.begin(), seg.end()) - seg.begin() - 1; 88 for(int i = 0; i < m; i++) { 89 LL l = seg[i], r = seg[i + 1], temp = 0; 90 for(int i = 1; i <= n; i++) 91 temp += ceil((LL)a[i], l); 92 LL d = C / temp; 93 if(d >= l && d < r && d > res) 94 res = d; 95 } 96 printf(Auto"\\n", res); 97 } 98 99 int main() { 100 init(); 101 solve(); 102 return 0; 103 }
然后我们来讲点神仙做法。142857 orz orz orz.....
不妨设$C = K + \\sum_{i = 1}^{n} a_{i}$
因为所有$\\left \\lceil \\frac{a_i}{d} \\right \\rceil \\geqslant 1$,所以$d\\leqslant \\left \\lfloor \\frac{C}{n} \\right \\rfloor$
设$d_0 = \\left \\lfloor \\frac{C}{n} \\right \\rfloor$。
假装已经顺利地求出了$d_0, d_1, d_2, \\cdots, d_k$,我们找到最大的$d_{k + 1}$满足:
$d_{k + 1}\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_k} \\right \\rceil \\leqslant C$
当$d_{k + 1} = d_k$的时候我们就找到最优解了。
感觉很玄学?那我来证明一下。
定理1 $d_{k + 1} \\leqslant d_{k}$
证明
- 当$k = 0$的时候,因为$\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_0} \\right \\rceil \\geqslant n$,所以$d_{1} = \\left \\lfloor \\frac{C}{\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_0} \\right \\rceil} \\right \\rfloor \\leqslant \\left \\lfloor\\frac{C}{n}\\right \\rfloor = d_0$。
- 当$k > 0$的时候,假设当$k = m - 1, (m \\geqslant 0)$时成立,考虑当$k = m$的时候,由$d_{k} \\leqslant d_{k - 1}$可得$\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_{k - 1}} \\right \\rceil \\leqslant \\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_{k}} \\right \\rceil $,然后可得$d_{k + 1} \\leqslant d_k$。
定理2 当$d_{k + 1} = d_{k}$,$d_k$是最优解
证明 假设存在$d > d_k$满足条件
- 显然$d \\leqslant d_0$。(不然直接不合法)
- 显然$d \\neq d_j\\ \\ (0 \\leqslant j < k)$。
- 假设$d_{j} < d < d_{j - 1}\\ \\ (0 < j \\leqslant k)$,那么$C \\geqslant d\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d} \\right \\rceil \\geqslant d\\sum_{i = 1}^{n} \\left \\lceil \\frac{a_i}{d_{j}} \\right \\rceil $
由迭代做法可知$d\\leqslant d_{j + 1}\\leqslant d_j$,矛盾。
显然$d = d_k$时是合法的,所以$d_k$是最优解。
时间复杂度感觉很低,但是我只会证它不超过$O(n\\sqrt{\\frac{C}{n}})$
Code
1 /** 2 * Codeforces 3 * Problem#831F 4 * Accepted 5 * Time: 31ms 6 * Memory: 0k 7 */ 8 #include <iostream> 9 #include <cassert> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <vector> 13 #include <queue> 14 #ifndef WIN32 15 #define Auto "%lld" 16 #else 17 #define Auto "%I64d" 18 #endif 19 using namespace std; 20 typedef bool boolean; 21 22 #define ll long long 23 24 const int N = 105; 25 26 int n; 27 ll C; 28 int ar[N]; 29 30 inline void init() { 31 scanf("%d"Auto, &n, &C); 32 for (int i = 0; i < n; i++) 33 scanf("%d", ar + i), C += ar[i]; 34 } 35 36 ll ceil(ll a, ll b) { 37 return (a + b - 1) / b; 38 } 39 40 inline void solve() { 41 ll dcur = C / n, dans; 42 do { 43 swap(dcur, dans), dcur = 0; 44 for (int i = 0; i < n; i++) 45 dcur += ceil(ar[i], dans); 46 dcur = C / dcur; 47 } while (dcur != dans); 48 printf(Auto"\\n", dans); 49 } 50 51 int main() { 52 init(); 53 solve(); 54 return 0; 55 }
更新日志
- 2018-1-28 补上jmr的做法
- 2018-10-22 给出证明
以上是关于Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力(的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #424 (Div. 2) A-C
Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力(
Codeforces Round #424 (Div. 2) D 思维 E set应用,树状数组
Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)
Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答
Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Cards Sorting(树状数组)