Uva 714 (抄书问题,二分查找+贪心)

题目链接在
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=655

这题要求最大值尽量小,最大值越小肯定越难,所以如果最大值可以是x1的话, 那么x2>x1肯定也可以,所以这里可以用binary search。

另外还要加greedy search,从最右边开始(因为题目规定S(1) 尽量小, 若S(1)一样则S(2)尽量小…),尽量把多的数放到一起(只要sum不大于目标值即可)。

代码如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> ans;

//test if we can divide the data array into x parts, with the max of the sum in each part not larger than x
bool P(vector<int>&data, int k, long long x) {
    int p1 = data.size()-1;
    long long tempSum = 0;
    ans.resize(0);

    while (p1 >= 0) {
        while ((tempSum <= x) && (p1>=k-2)) {
            tempSum += data[p1--];
         }

        p1++; //bounce back because p1 moves too much.

        ans.push_back(p1);
        k--;

        if (p1<k-1) {
           return false;
        }

        tempSum = 0;

        if (k==1) {
            long long sum1 = 0;
            for (int i=0; i<=p1; i++) {
                sum1 += data[i];
            }
            if (sum1 <= x) {
                return true;
            }
            else {
                return false;
            }
        }

    }

}

int main()
{
    int n,k,T;
    vector<int> data;

    cin>>T;
    while(T--) {
       long long sum = 0;
       int maxi = 0;
       cin>>n>>k;
       data.resize(n);
       for (int i=0; i<n; i++){
           cin>>data[i];
           sum+=data[i];
           maxi=max(maxi, data[i]);
       }

       if (k==1) {
           for (vector<int>::iterator it = data.begin(); it<data.end(); it++)
               cout<<*it<<" ";
           cout<<endl;
           continue;
       }

       //binary search with P(x)
       long long l = 0;
       long long r = sum;

       while (l<r) {
           long long m = l + (r-l)/2;
           if (P(data, k, m)) {
               r = m;   //the answer is less than or equal to m
           }
           else {
               l = m+1; //the answer should be larger than m
           }
       }

       P(data, k, l);

       vector<int>::reverse_iterator  r_it = ans.rbegin();
       for (int i=0; i<data.size(); i++) {
          cout<<data[i]<<" ";
          if (i==*r_it) {
              cout<<"/ ";
              ++r_it;
          }
          cout<<endl;
       }
    }

    return 0;
}

设所有n个元素的SUM和为M, 二分次数为logM,每次整个数组都扫一遍。所以复杂度为O(nlogM)。

这题要注意跟sum有关的变量都用long long,不然可能溢出。我在Uva上提交的结果是Presentation Error。应该是结果对,但输出不符合要求。不知道具体什么原因,以后再查,欢迎有知道原因的同学留言。也欢迎大家对我的代码提出改进意见。

猜你喜欢

转载自blog.csdn.net/roufoo/article/details/78500330