zoukankan      html  css  js  c++  java
  • Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F)

    题目传送门

      传送门I

      传送门II

      传送门III

    题目大意

      求一个满足$dsum_{i = 1}^{n} left lceil frac{a_i}{d} ight ceil - sum_{i = 1}^{n} a_{i} leqslant K$的最大正整数$d$。

      整理一下可以得到条件是$dsum_{i = 1}^{n} left lceil frac{a_i}{d} ight ceil leqslant K + sum_{i = 1}^{n} a_{i}$

      有注意到$left lceil frac{a_i}{d} ight ceil$的取值个数不会超过$2left lceil sqrt{a_i} ight ceil$。

      证明考虑对于$1 leqslant d leqslant left lceil sqrt{a_i} ight ceil$,至多根号种取值,当$d >left lceil sqrt{a_i} ight ceil$的时候,取值至多为$1, 2, cdots, left lceil sqrt{a_i} ight ceil$,所以总共不会超过$2left lceil sqrt{a_i} ight ceil$个取值。

      所以我们把所有$left lceil frac{a_i}{d} ight ceil$的取值当成一个点,安插在数轴上,排个序,就愉快地找到了所有分段了。因为每一段内的$d$都是等价的,所以只需要用每一段的左端点计算和,然后判断$left lfloor frac{K + sum_{i = 1}^{n} a_{i}}{sum_{i = 1}^{n} left lceil frac{a_i}{d} ight ceil} ight floor$是否在区间内,如果是就用它去更新答案。

    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"
    ", res);
     97 }
     98 
     99 int main() {
    100     init();
    101     solve();
    102     return 0;
    103 }
    Brute force

      然后我们来讲点神仙做法。142857 orz orz orz.....

      不妨设$C = K + sum_{i = 1}^{n} a_{i}$

      因为所有$left lceil frac{a_i}{d} ight ceil geqslant 1$,所以$dleqslant left lfloor frac{C}{n} ight floor$

      设$d_0 =  left lfloor frac{C}{n} ight floor$。

      假装已经顺利地求出了$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} ight ceil 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} ight ceil geqslant n$,所以$d_{1} = left lfloor frac{C}{sum_{i = 1}^{n} left lceil frac{a_i}{d_0} ight ceil} ight floor leqslant left lfloorfrac{C}{n} ight floor = 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}} ight ceil leqslant sum_{i = 1}^{n} left lceil frac{a_i}{d_{k}} ight ceil $,然后可得$d_{k + 1} leqslant d_k$。

    定理2 当$d_{k + 1} = d_{k}$,$d_k$是最优解

      证明 假设存在$d > d_k$满足条件

    • 显然$d leqslant d_0$。(不然直接不合法)
    • 显然$d eq d_j   (0 leqslant j < k)$。
    • 假设$d_{j} < d < d_{j - 1} (0 < j leqslant k)$,那么$C geqslant dsum_{i = 1}^{n} left lceil frac{a_i}{d} ight ceil geqslant dsum_{i = 1}^{n} left lceil frac{a_i}{d_{j}} ight ceil $
      由迭代做法可知$dleqslant d_{j + 1}leqslant d_j$,矛盾。

      显然$d = d_k$时是合法的,所以$d_k$是最优解。

      时间复杂度感觉很低,但是我只会证它不超过$O(nsqrt{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"
    ", dans);
    49 }
    50 
    51 int main() {
    52     init();
    53     solve();
    54     return 0;
    55 }

    更新日志

    • 2018-1-28 补上jmr的做法
    • 2018-10-22 给出证明
  • 相关阅读:
    HDOJ 4747 Mex
    HDU 1203 I NEED A OFFER!
    HDU 2616 Kill the monster
    HDU 3496 Watch The Movie
    Codeforces 347A A. Difference Row
    Codeforces 347B B. Fixed Points
    Codeforces 372B B. Hungry Sequence
    HDU 1476 Sudoku Killer
    HDU 1987 How many ways
    HDU 2564 词组缩写
  • 原文地址:https://www.cnblogs.com/yyf0309/p/7193163.html
Copyright © 2011-2022 走看看