• 二分专题(不定期更新)


    1、POJ 3258 River Hopscotch

      题意:给出小溪的长度L,给出河中石头数N和最多可移动的石头数M,使得每两颗相邻石头、起点与第一颗石头、终点与最后一颗石头之间的最小距离最大。

      思路:二分最小距离,然后把间距小于该距离的石头移除,如果移除的石头数大于M,说明该距离太大,否则可以尝试增大该距离。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 int L, N, M;
     5 int st, ed;
     6 const int maxn = 50005;
     7 int Rocks[maxn];
     8 bool Judge(int dis)
     9 {
    10     int rmvrocks = 0;
    11     int tdis = 0;
    12     int refpos = 0;
    13     int tnumrocks = 0;
    14     for (int i = 0; i < N;)
    15     {
    16         tnumrocks = 0;
    17         while (i<N&&Rocks[i] - refpos < dis) tnumrocks++,i++;
    18         rmvrocks += tnumrocks;
    19         refpos = Rocks[i];
    20         i++;
    21     }
    22     if (tnumrocks == 0 && L - Rocks[N - 1] < dis) rmvrocks++;
    23     if (rmvrocks > M) return false;
    24     else return true;
    25 }
    26 int main()
    27 {
    28     while (cin >> L)
    29     {
    30         cin >> N >> M;
    31         for (int i = 0; i < N; i++) cin >> Rocks[i];
    32         sort(Rocks, Rocks + N);
    33         int mindis = Rocks[0];
    34         for (int i = 1; i < N; i++)
    35             if (Rocks[i] - Rocks[i - 1] < mindis) mindis = Rocks[i] - Rocks[i - 1];
    36         if (L - Rocks[N - 1] < mindis) mindis = L - Rocks[N - 1];
    37         int l = mindis, r = L;
    38         while (l <= r)
    39         {
    40             int mid = (l + r) / 2;
    41             if (Judge(mid)) l = mid + 1;
    42             else r = mid - 1;
    43         }
    44         cout << r << endl;
    45     }
    46     return 0;
    47 }
    View Code

    2、POJ 3104 Drying

      题意:给出n件衣服,每件衣服上都有wi的水分,每次要么把一件衣服放在烘炉上,每分钟至多减少k的水分,要么自然烘干,每分钟减少1的水分,同一时间最多只能把一件衣服放在烘炉上。求所有衣服都烘干的最小时间。

      思路:二分总时间,记为为t,设此时所需用烘炉的时间为tx=0.为使总时间最小,那么要尽可能利用烘炉,直至所有衣服被烘干之前的每分钟都有把某一件衣服放在烘炉上,我们则统计出该时间,如果小于等于t,说明我们还可以尝试减少时间,否则,只能增大时间。接下来要统计出tx.第i件衣服的水分为wi.如果wi<t,则让其自然烘干即可;否则,由于只需要ceil((wi-x)/(k-1))的用烘炉的时间,剩下的水分让其自然烘干。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cmath>
     4 #include <cstdio>
     5 using namespace std;
     6 #define MAXN 100000+10
     7 #define LL long long
     8 int n, k;
     9 int wat[MAXN];
    10 
    11 bool Judge(int x)
    12 {
    13     LL t = 0;
    14     for (int i = 0; i<n; i++)
    15     {
    16         if (wat[i]>x)
    17         {
    18             int xx = ceil((wat[i] - x)*1.0 / (k - 1));
    19             t += xx;
    20         }
    21         if (t>x)return false;
    22     }
    23 
    24     if (t>x)return false;
    25     else return true;
    26 }
    27 int main()
    28 {
    29     while (~scanf("%d", &n))
    30     {
    31         int l = 1, r = 0;
    32         for (int i = 0; i<n; i++)
    33         {
    34             scanf("%d", &wat[i]);
    35             r = max(r, wat[i]);
    36         }
    37         scanf("%d", &k);
    38 
    39         if (k == 1)
    40         {
    41             printf("%d
    ", r);
    42             continue;
    43         }
    44         int mid = 0;
    45         while (l <= r)
    46         {
    47             mid = (l + r) / 2;
    48             if (Judge(mid))
    49             {
    50                 r = mid - 1;
    51             }
    52             else
    53                 l = mid + 1;
    54         }
    55         printf("%d
    ",l);
    56     }
    57     return 0;
    58 }
    View Code

     3、poj2976-Dropping tests(0-1分数规划)

      题意:有n次测试,每次测试对ai道题,总共bi道题。现在,你可以在最多除去k次的测试,使得剩下的测试中总正确率(剩下测试的对的总题数/剩下测试的总题数)最高。

      思路:二分总正确率,对于当前假设正确率x,对于每个测试,其额外做对的题目为ai-x*bi(也可以看成贡献度),然后去掉最小的k次,累加前面大的n-k次,如果算出来正确率可以超过x,则可以尝试增大x,否则,只能减小x.

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 1010;
     5 int n, k;
     6 struct Score
     7 {
     8     int a;
     9     int b;
    10 }tests[maxn];
    11 long long suma, sumb;
    12 
    13 double tt;//假设的当前正确率
    14 bool Cmp(const Score&a, const Score&b)
    15 {
    16     return a.a - tt*a.b > b.a - tt*b.b;//对当前正确率贡献度大的排前面
    17 }
    18 
    19 bool Judge(double rt)
    20 {
    21     tt = rt;
    22     sort(tests, tests + n, Cmp);
    23     long long sum1 = 0, sum2 = 0;
    24     for (int i = 0; i < n; i++)
    25     {
    26         if(i<n-k)sum1 += tests[i].a, sum2 += tests[i].b;
    27         else if (tests[i].a - rt*tests[i].b > 1e-4) sum1 += tests[i].a, sum2 += tests[i].b;
    28     }
    29     if (1.0*sum1 / sum2 >= rt) return true;
    30     else return false;
    31 }
    32 
    33 int main()
    34 {
    35     while (cin >> n >> k, n != 0 || k != 0)
    36     {
    37         suma = sumb = 0;
    38         for (int i = 0; i < n; i++)
    39         {
    40             cin >> tests[i].a;
    41             suma += tests[i].a;
    42         }
    43         for (int i = 0; i < n; i++)
    44         {
    45             cin >> tests[i].b;
    46             sumb += tests[i].b;
    47         }
    48         double L = 1.0*suma / sumb;
    49         double R = 1.0;
    50         while (R - L > 1e-4)
    51         {
    52             double mid = (L + R) / 2;
    53             if (Judge(mid)) L = mid;
    54             else R = mid;
    55         }
    56         printf("%.lf
    ", L*100);
    57     }
    58     return 0;
    59 }
    View Code

    4、poj 3685 Matrix

      题意:对于n*n的矩阵,第i行第j列的数字为i*i + 100000 * i + j*j - 100000 * j + i*j。求第m小的元素值。

      思路:从式子可以看出每列中的数字按行递增。然后二分答案,然后对于每列二分,找到第一个大于等于该答案的位置,然后就可以知道该列中小于该答案的数字的个数。统计出所有的个数,如果个数大于m,说明该答案还可以减小,否则的话需要增大。

     1 //先对答案进行二分,求满足小于等于该答案的个数(求法:由于每列从上到下的值递增,对每一列找到第一个大于答案的值,然后累加个数),若个数太多,则说明答案太大,否则太小。
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 const long long INF = 1LL << 50;
     6 long long f(long long i, long long j)
     7 {
     8     return i*i + 100000 * i + j*j - 100000 * j + i*j;
     9 }
    10 long long n, m;
    11 bool Judge(long long tans)
    12 {
    13     long long num = 0;
    14     for (int j = 1; j <= n; j++)
    15     {
    16         int l = 1, r = n;
    17         while (l <= r)
    18         {
    19             int mid = (l + r) / 2;
    20             if (f(mid, j) > tans)
    21             {
    22                 r = mid - 1;
    23             }
    24             else l = mid + 1;
    25         }
    26         num += l - 1;
    27     }
    28     if (num >= m) return true;
    29     else return false;
    30 }
    31 int main()
    32 {
    33     int t;
    34     cin >> t;
    35     while (t--)
    36     {
    37         scanf("%lld%lld", &n, &m);
    38         long long R = INF, L = -INF;
    39         while (L <= R)
    40         {
    41             long long mid = (L + R) >> 1;
    42             if (Judge(mid))
    43             {
    44                 R = mid - 1;
    45             }
    46             else L = mid + 1;
    47         }
    48         printf("%lld
    ", L);
    49     }
    50     return 0;
    51 }
    View Code

    5、poj 3662 Telephone Linse

      题意:有N个电线杆,给出P条可以连接的电线,其中K条可以免费,求存在1到N的一条路径,若连接的电线数目小于K条,则为0;若大于,则求其除去K条电线后剩余的电线长度最大值的最小值;若不存在路径,为-1.

      思路:最优情况下免费的K条肯定取需要连接的电线从大到小前K条。那么我们二分这个最大长度mid,把大于该长度的电线的权值记为1,小于等于该长度的电线的权值记为0,求一次从1开始的最短路径,dis[N]即为大于mid长度的电线条数,如果该条数小于等于K,说明我们至多需要支付mid的价格,接下来看能不能再缩小mid;否则,只能增大mid;如果不存在路径,直接输出-1;如果mid为0时dis[N]小于等于K,则可直接输出0.

      1 #include<iostream>
      2 #include<memory.h>
      3 #include<vector>
      4 #include<queue>
      5 using namespace std;
      6 struct node
      7 {
      8     int to;
      9     int length;
     10     int weight;
     11     node(int t= 0, int l = 0,int wt=0):to(t),length(l),weight(wt){ }
     12 };
     13 vector<vector<node> >m;
     14 int dis[1005];
     15 int path[1005];
     16 bool vis[1005];
     17 int cnt[1005];
     18 int n, p, k;
     19 const int INF = 0x7fffffff;
     20 bool flag = true;
     21 bool SPFA(int src)
     22 {
     23     memset(vis, 0, sizeof(vis));
     24     memset(cnt, 0, sizeof(cnt));
     25     for (int i = 1; i <= n; i++)
     26     {
     27         dis[i] = INF;
     28         path[i] = src;
     29     }
     30     queue<int>q;
     31     q.push(src);
     32     dis[src] = 0, vis[src] = true;
     33     cnt[src]++;
     34     while (!q.empty())
     35     {
     36         int v = q.front();
     37         q.pop();
     38         vis[v] = false;
     39         int sz = m[v].size();
     40         for (int i = 0; i < sz; i++)
     41         {
     42             int u = m[v][i].to;
     43             if (dis[v] + m[v][i].weight < dis[u])
     44             {
     45                 dis[u] = dis[v] + m[v][i].weight;
     46                 path[u] = v;
     47                 if (!vis[u])
     48                 {
     49                     q.push(u);
     50                     vis[u] = true;
     51                     cnt[u]++;
     52                     if (cnt[u] > n) return false;
     53                 }
     54             }
     55         }
     56     }
     57     return true;
     58 }
     59 void Dij(int src)
     60 {
     61     memset(dis, -1, sizeof(dis));
     62     memset(vis, 0, sizeof(vis));
     63     memset(path, 0, sizeof(path));
     64     int sz = m[src].size();
     65     for (int i = 0; i < sz; i++) dis[m[src][i].to] = m[src][i].weight,path[m[src][i].to]=src;
     66     for (int i = 1; i <= n; i++) if (dis[i] == -1) dis[i] = INF;
     67     vis[src] = true, dis[src] = 0;
     68     for (int i = 1; i <= n - 1; i++)
     69     {
     70         int u = src, min = INF;
     71         for (int i = 1; i <= n; i++)
     72         {
     73             if (!vis[i] && dis[i] < min) u = i, min = dis[i];
     74         }
     75         vis[u] = true;
     76         sz = m[u].size();
     77         for (int i = 0; i < sz; i++)
     78         {
     79             int v = m[u][i].to;
     80             if (!vis[v] && dis[u] + m[u][i].weight < dis[v])
     81             {
     82                 dis[v] = dis[u] + m[u][i].weight;
     83                 path[v] = u;
     84             }
     85         }
     86     }
     87 }
     88 bool Judge(int mid)
     89 {
     90     for (int i = 1; i <= n; i++)
     91     {
     92         int sz = m[i].size();
     93         for (int j = 0; j < sz; j++)
     94         {
     95             if (m[i][j].length > mid) m[i][j].weight = 1;
     96             else m[i][j].weight = 0;
     97         }
     98     }
     99     //SPFA(1);
    100     Dij(1);
    101     if (dis[n] == INF) flag = false;
    102     if (dis[n] <= k) return true;
    103     else return false;
    104 }
    105 int main()
    106 {
    107     while (~scanf("%d%d%d", &n, &p, &k))
    108     {
    109         m.clear();
    110         for (int i = 0; i <= n; i++) m.push_back(vector<node>());
    111         int L = 0, R = 0;
    112         for (int i = 1; i <= p; i++)
    113         {
    114             int v, u, l;
    115             scanf("%d%d%d", &v, &u, &l);
    116             m[v].push_back(node(u, l));
    117             m[u].push_back(node(v, l));
    118             if (l > R) R = l;
    119         }
    120         flag = true;
    121         if (Judge(0))
    122         {
    123             printf("0
    ");
    124         }
    125         else if (!flag)
    126         {
    127             printf("-1
    ");
    128         }
    129         else
    130         {
    131             while (L <= R)
    132             {
    133                 int mid = (L + R) / 2;
    134                 if (Judge(mid)) R = mid - 1;
    135                 else L = mid + 1;
    136             }
    137             printf("%d
    ", L);
    138         }
    139     }
    140     return 0;
    141 }
    View Code

    6、UVA 1555 - Garland(推公式,贪心,二分搜索)

      题意:有一个电线,给出最左边的电灯挂的高度,第i盏灯的高度为Hi = (H i-1 + H i+1)/2 - 1,共要挂n盏灯,并且高度不能低于地面。求最右边那盏灯的最低高度。

      思路:Hi = (H i-1 + H i+1)/2 - 1转换为Hi=2*H(i-1)+2-H(i-2)。二分第二盏灯的高度,如果没有灯的高度低于地面,则看看能不能再降低,否则只能增大。

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int n;
     5 double A, B;
     6 bool Judge(double x)
     7 {//Hi=2*H(i-1)+2-H(i-2)
     8     double h1 = A, h2 = x,h3;
     9     for (int i = 3; i <= n; i++)
    10     {
    11         h3 = 2 * h2 + 2 - h1;
    12         if (h3 < 0) return false;
    13         h1 = h2, h2 = h3;
    14     }
    15     B = h3;
    16     return true;
    17 }
    18 int main()
    19 {
    20     while (~scanf("%d%lf", &n, &A))
    21     {
    22         double L = 0, R = A;
    23         while (R - L >= 1e-6)
    24         {
    25             double mid = (R + L) / 2;
    26             if (Judge(mid)) R = mid;
    27             else L = mid;
    28         }
    29         printf("%.2lf
    ", B);
    30     }
    31     return 0;
    32 }
    View Code
  • 相关阅读:
    2019年主机游戏将走下坡路
    关于敏捷开发的26个心得
    CSS3弹性布局内容对齐(justify-content)属性使用具体解释
    (cLion、RubyMine、PyCharm、WebStorm、PhpStorm、Appcode、Clion、Idea) 万能破解,获取自己的注冊码
    hdoj-1212-Big Number【大数取余&amp;简单题】
    gitlab https
    gitlab smtp设置
    GitLab: API is not accessibl
    Could not find modernizr-2.6.2 in any of the sources GitLab: API is not accessible
    gitlab
  • 原文地址:https://www.cnblogs.com/ivan-count/p/7228957.html
Copyright © 2020-2023  润新知