• 最大化最小值


    POJ3258

    题意:

    有一堆牛要过河,河的长度是 L,河中间有N个石头,牛只能踩着石头过河,问去掉M个石头后(去掉这M个石头的方式是随机的),牛能走的石头间距最小值中,最大的那一个是多少,输出距离。

    开始和最后的两块石头不能搬走。

    解法:

    最大化石头间距的最小值

    二分距离,从左到右遍历所有的石头(包括首尾),在判断距离之内不停的搬走石头,当石头总数大于M的时候即是错误。

    代码如下:

     1 int L, M, N;
     2 int pos[MAXN];
     3 
     4 bool C(int x) {
     5     int sum = 0, last = 0;
     6     for (int i = 1; i <= N + 1; i++) {
     7         if (pos[i] - pos[last] < x) {
     8             sum++;
     9             if (sum > M) {
    10                 return false;
    11             }
    12         } else {
    13             last = i;
    14         }
    15     }
    16     return true;
    17 }
    18 
    19 void jojo() {
    20     sort(pos, pos + N + 1);
    21     int lb = 0, ub = L + 1;
    22     while (ub - lb > 1) {
    23         int mid = (ub + lb) / 2;
    24         if (C(mid)) {
    25             // cout << "true: " << mid << endl;
    26             lb = mid;
    27         } else {
    28             // cout << "false: " << mid << endl;
    29             ub = mid;
    30         }
    31     }
    32     cout << lb << endl;
    33 }
    34 
    35 int main() {
    36 #ifndef ONLINE_JUDGE
    37     freopen("input.txt", "r", stdin);
    38 #endif  // !ONLINE_JUDGE
    39     L = READ(), N = READ(), M = READ();
    40     for (int i = 1; i <= N; i++) pos[i] = READ();
    41     pos[0] = 0;
    42     pos[N + 1] = L;
    43     jojo();
    44     return 0;
    45 }

    POJ3273

    题意:

    有N个数,要求按顺序划分成M组,使得这M组数的和的最大值最小。

    解法:

    最小化最大值

    二分M组数的和,遍历所有的数,累加,当其大于二分值的时候将计数器加1,当最后如果计数器的值大于M,则为非法。

    这里其实有两种情况,假如要准确划分7组:

    1. 那么假如前面的划分成 3 组之后,后面一共3个数,每个都小于二分值,但不够分成 4 组怎么办?

    2. 或者前面已经划分成了 6 组,后面还有3个数,每个都超过了二分值,怎么办?

    对于第一种情况:我们判定的是真,那么说明二分值可以进一步缩小。

    对于第二种情况:那么肯定超过了M-1,所以返回false

    还有一点注意的是,对于二分的值,如果我们想要缩小范围,那么请把上下界的范围扩大1,这样可以避免WA。

    啧啧,简直了。

     1 int N, M;
     2 int d[MAXN];
     3 int mx, mn;
     4 
     5 bool C(int x) {
     6     int last = 0, num = 0, sum = 0;
     7     for (int i = 0; i < N; i++) {
     8         if (sum + d[i] <= x) {
     9             sum += d[i];
    10         } else {
    11             num++;
    12             sum = d[i];
    13         }
    14     }
    15     if (num + 1 > M) {
    16         return false;
    17     } else {
    18         return true;
    19     }
    20 }
    21 
    22 void solve() {
    23     int ub = mx + 1, lb = mn;
    24     while (ub - lb > 1) {
    25         int mid = (ub + lb) >> 1;
    26         if (C(mid)) {
    27             ub = mid;
    28         } else {
    29             lb = mid;
    30         }
    31     }
    32     cout << ub << endl;
    33     return;
    34 }
    35 
    36 int main() {
    37 #ifndef ONLINE_JUDGE
    38     freopen("input.txt", "r", stdin);
    39 #endif  // !ONLINE_JUDGE
    40     while (scanf("%d%d", &N, &M) != EOF) {
    41         mx = 0, mn = 0;
    42         for (int i = 0; i < N; i++) {
    43             scanf("%d", &d[i]);
    44             mx += d[i];
    45             mn = min(mn, d[i]);
    46         }
    47         solve();
    48     }
    49     return 0;
    50 }

    POJ3104

    题意:

    每件衣服都有一定单位水分,在不适用烘干器的情况下,每件衣服每分钟自然流失1个单位水分,但如果使用了烘干机则每分钟流失K个单位水分,但是遗憾是只有1台烘干机,每台烘干机同时只能烘干1件衣服,请问要想烘干N件衣服最少需要多长时间?

    解法:

    二分首先要先考虑是不是有单调关系,就是越怎么样就越怎么样。

    这题,时间越多,就越可以烘干,所以二分时间。

    先对水量排个序,每次二分时间 t,也就是说在没有烘干机的情况下,每件衣服可以减少 t 水分。那么比 t 小的衣服就不用烘干,比 t 大的就一定要烘干。

    计算每一件衣服要烘干的时间,也就是$frac{a[i]-t}{k-1}$,因为这一分钟选择了烘干,意味着在原来基础上减去 k-1水分,然后有余数就要再多烘干一分钟。最后统计一下烘干时间是不是大于t就行了。

    二分复杂度是log1e9,每次遍历是O(n),可过。

    这题的锅:首先要用LL,因为最坏的情况k为2,水量全都1e9。然后特判一下k=1时,不然除0会re

     1 LL N, K;
     2 LL a[MAXN];
     3 LL mx = -1;
     4 
     5 bool C(LL t) {
     6     int i = lower_bound(a, a + N, t) - a;
     7     LL sum = 0;
     8     for (; i < N; i++) {
     9         if ((a[i] - t) % (K - 1) == 0) {
    10             sum += (a[i] - t) / (K - 1);
    11         } else {
    12             sum += ((a[i] - t) / (K - 1) + 1);
    13         }
    14     }
    15     if (sum > t) {
    16         return false;
    17     } else {
    18         return true;
    19     }
    20 }
    21 
    22 void solve() {
    23     sort(a, a + N);
    24     if (K == 1) {
    25         printf("%lld
    ", mx);
    26         return;
    27     }
    28     LL ub = LLINF, lb = 0;
    29     while (ub - lb > 1) {
    30         LL mid = (ub + lb) >> 1;
    31         if (C(mid)) {
    32             ub = mid;
    33         } else {
    34             lb = mid;
    35         }
    36     }
    37     printf("%lld
    ", ub);
    38     return;
    39 }
    40 
    41 int main() {
    42 #ifndef ONLINE_JUDGE
    43     freopen("input.txt", "r", stdin);
    44 #endif  // !ONLINE_JUDGE
    45     scanf("%lld", &N);
    46     for (int i = 0; i < N; i++) {
    47         scanf("%lld", &a[i]);
    48         mx = max(a[i], mx);
    49     }
    50     scanf("%lld", &K);
    51     solve();
    52     return 0;
    53 }
  • 相关阅读:
    C#中IEnumerable、ICollection、IList、List之间的区别
    H5中画图标签Canvas---画矩形,画线,画圆,渐变色,图形载入
    centos启用ftp功能
    CentOS 7 安装FTP服务器(vsftpd)
    Linux下如何修改用户默认目录
    Centos搭建FTP服务器
    MyBatis 示例之存储过程
    MyBatis:MyBatis操作MySQL存储过程
    mybatis的select、insert、update、delete语句
    日常运维中的相关日志切割处理方法总结 [Logrotate、python、shell脚本实现 ]
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/12333352.html
Copyright © 2020-2023  润新知