zoukankan      html  css  js  c++  java
  • 【u102】数列分段2

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    对于给定的一个长度为N的正整数数列A[i],现要将其分成M(M≤N)段,并要求每段连续,且每段和的最大值最小。 关于最大值最小: 例如一数列4 2 4 5 1要分成3段 将其如下分段: [4 2][4 5][1] 第一段和为6,第2段和为9,第3段和为1,和最大值为9。 将其如下分段: [4][2 4][5 1] 第一段和为4,第2段和为6,第3段和为6,和最大值为6。 并且无论如何分段,最大值不会小于6。 所以可以得到要将数列4 2 4 5 1要分成3段,每段和的最大值最小为6。

    【输入格式】

    输入文件divide_b.in的第1行包含两个正整数N,M,第2行包含N个空格隔开的非负整数A[i],含义如题目所述。

    【输出格式】

    输出文件divide_b.out仅包含一个正整数,即每段和最大值最小为多少。

    【数据规模】

    对于20%的数据,有N≤10; 对于40%的数据,有N≤1000; 对于100%的数据,有N≤100000,M≤N, A[i]之和不超过109。

    Sample Input1

    5 3
    4 2 4 5 1

    Sample Output1

    6
    【题目链接】:http://noi.qz5z.com/viewtask.asp?id=u102

    【题解】

    二分答案题;
    二分每段区间里面累加和的最大值是多少;
    然后O(n)处理出最少能够分成多少段设为L(能放进这一段就放进去(如果不超过上限))
    显然二分的最大值越大,L越小;
    如果L<=m则表示这个最大值是可行的;则让二分的最大值更小一点;这样每段里面包含的数字个数就会变小;总的区间数就会增加(也可能不变);
    如果L>m则表示这个最大值太小了,分的段就变多了;则最大值要变大一点;这样每段里面元素变多了;分段数就会变小;
    这样就能让L逼近M,且同时我们的最大值也是最小的;直到增加到答案时为止,这时肯定能符合要求,因为最后的答案是存在的;而我们在不断逼近答案;

    【完整代码】

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <set>
    #include <map>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <stack>
    #include <string>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    void rel(LL &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t) && t!='-') t = getchar();
        LL sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    void rei(int &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t)&&t!='-') t = getchar();
        int sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    const int MAXN = 1e5+100;
    const int dx[5] = {0,1,-1,0,0};
    const int dy[5] = {0,0,0,-1,1};
    const double pi = acos(-1.0);
    
    int n,L;
    int a[MAXN];
    
    int f(int ma)
    {
        int now = a[1],d = 1;
        rep1(i,2,n)
            if (a[i]+now>ma)
            {
                now = a[i];
                d++;
            }
            else
                now+=a[i];
        return d;
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        rei(n);rei(L);
        int l = 0,r = 0;
        rep1(i,1,n)
            rei(a[i]),l = max(l,a[i]),r+=a[i];
        int ans = -1;
        while (l <= r)
        {
            int m = (l+r)>>1;
            if (f(m)<=L)
            {
                ans = m;
                r = m-1;
            }
            else
                l = m+1;
        }
        cout << ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    POJ 1681 Painter's Problem(高斯消元法)
    HDU 3530 Subsequence(单调队列)
    HDU 4302 Holedox Eating(优先队列或者线段树)
    POJ 2947 Widget Factory(高斯消元法,解模线性方程组)
    HDU 3635 Dragon Balls(并查集)
    HDU 4301 Divide Chocolate(找规律,DP)
    POJ 1753 Flip Game(高斯消元)
    POJ 3185 The Water Bowls(高斯消元)
    克琳:http://liyu.eu5.org
    WinDbg使用
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626918.html
Copyright © 2011-2022 走看看