UVa 714 - Copying Books 二分答案

题目链接:714 - Copying Books

解题思路

具体处理方法见代码

/**************************************************************
    Problem:
    User: youmi
    Language: C++
    Result: Accepted
    Time:
    Memory:
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define sclld(a) scanf("%I64d",&a)
#define pt(a) printf("%d\n",a)
#define ptlld(a) printf("%I64d\n",a)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep_1(i,n) for(int i=n;i>=1;i--)
#define rep_0(i,n) for(int i=n-1;i>=0;i--)
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define lson (step<<1)
#define rson (lson+1)
#define esp 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl

using namespace std;
typedef long long ll;

int n,k;

const int maxn=500+10;
ll a[maxn];
map<int,int>m;//用来标记1-n哪些位置应该有“/”符号的
int main()
{
    //freopen("in.txt","r",stdin);
    int T_T;
    scanf("%d",&T_T);
    for(int kase=1;kase<=T_T;kase++)
    {
        sc2(n,k);
        ll l=0,r=0;
        rep1(i,n)
        {
            sclld(a[i]);
            l=Max(l,a[i]);//二分下限肯定是最大值
            r+=a[i];//上限自然是所有的总和
        }
        int tot=0;
        ll cur=r;
        ll temp;
        while(l<r)//每种方法都有其区块和的最大值,比如白皮书说的7,9.所以我们二分找满足分块条件的最大区块和当中的最小值
        {//比如白皮书上的案例,7<9,所以我们找到了7
            tot=0;
            temp=0;
            //printf("l->%I64d cur->%I64d r->%I64d\n",l,cur,r);
            for(int i=n;i>=1;i--)//从末尾开始统计(其实这里从头开始也可以,因为我们是找最小的分块条件),每次都贪心使后面的越大,那么前面的自然就越小了
            {
                //printf("tot->%d temp->%I64d \n",tot,temp);
                temp+=a[i];
                if(temp>cur)
                {
                    ++tot;
                    i++;//因为temp加上a[i]就超过了cur,所以我们下一块的最右边应该是a[i],所以这里i++与for循环里的i--抵消
                    //printf("%d %d %I64d\n",tot,i-1,temp-a[i-1]);
                    temp=0;
                    if(tot==k)//分了k次,那么总共有k+1块,也就是说这种情况下cur太小了
                    {
                        l=cur+1;
                        cur=(l+r)>>1;
                        break;
                    }
                }
            }
            if(tot<k)//用cur分块结果分的块不够多,比如可能只分了一块,所以这种情况cur太大了
            {
                r=cur;
                cur=(l+r)>>1;
            }
        }//while循环后,我们找到了一个最小的满足分块条件的区块和最大值,当前cur值即为该值,然后贪心从后面开始来
            tot=0;
            temp=0;
            m.clear();
            for(int i=n;i>=1;i--)
            {
                temp+=a[i];
                if(temp>cur)
                {
                    m[i++]=1;
                    ++tot;
                    temp=0;
                }
            }
        k--;
        int id=1;
        while(tot<k)//如果按cur分的块数少于cur,比如100,100,100,100,100,这种情况,分4块则cur最小满足条件应该是200,按200从后分,得到100/100 100/100 100,分少了
        {//那么我们在100/100 100/100 100中随便插一块板也是满足条件的,为了使前面尽量少,所以我应该把板插前面,因此从1开始搜索
            if(!m[id])
            {
                m[id]=1;
                tot++;
            }
            id++;
        }
        //ptlld(r);
        rep1(i,n)
        {
            printf("%lld%c",a[i],i==n?‘\n‘:‘ ‘);
            if(m[i])
            {
                printf("/ ");
            }
        }
    }
    return 0;
}
时间: 2024-10-16 17:43:38

UVa 714 - Copying Books 二分答案的相关文章

uva 714 Copying Books (二分)

uva 714 Copying Books Before the invention of book-printing, it was very hard to make a copy of a book. All the contents had to be re-written by hand by so called scribers. The scriber had been given a book and after several months he finished its co

uva 714 - Copying Books(贪心 最大值最小化 二分)

题目描述开头一大堆屁话,我还仔细看了半天..其实就最后2句管用.意思就是给出n本书然后要分成k份,每份总页数的最大值要最小.问你分配方案,如果最小值相同情况下有多种分配方案,输出前面份数小的,就像字典序输出从小到大一样的意思. 这里用到贪心的方法,定义f(x)为真的条件是满足x为最大值使n本书分成k份,那么就是求x的最小值.如何确定这个x就是用的二分法,x一定大于0小于所有值的合,不断的二分再判断是否成立,成立就取左半边,不成立说明太小了就取右半边,写的时候还是没有把二分法理解透彻,我还怕会丢失

【NOIP提高组2015D2T1】uva 714 copying books【二分答案】——yhx

Before the invention of book-printing, it was very hard to make a copy of a book. All the contents hadto be re-written by hand by so called scribers. The scriber had been given a book and after severalmonths he finished its copy. One of the most famo

UVa 714 Copying Books(贪心 二分)

题意  把m数分成k组  使每组数的和的最大值最小  如果有多种分法 靠前的组的和尽量小 关键是找出那个最小的最大值   可以通过二分来找出  开始左端点为m个数中最大的数  右端点为m个数的和  若中点能将m个数分为小于等于k组  比它大的肯定都是可以的  中点变为右端点   否则中点变成左端点 然后就可以贪心逆向模拟了  从后往前每组选择尽量多的数直到剩下的数等于组数 #include <bits/stdc++.h> using namespace std; typedef long lo

UVA 714 Copying Books 抄书 (二分)

题意:把一个包含m个正整数的序列划分成k个非空的连续子序列.使得所有连续子序列的序列和Si的最大值尽量小. 二分,每次判断一下当前的值是否满足条件,然后修改区间.注意初始区间的范围,L应该为所有正整数中的最大值,否则应该判断时注意.输出解的时候要使字典序最小,所以从后面贪心. #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxm = 501; ll p[maxm]; bool vis[

UVa 714 Copying books 贪心+二分 最大值最小化

题目大意: 要抄N本书,编号为1,2,3...N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的.每个抄写员的速度是相同的,求所有书抄完所用的最少时间的分配方案. 题目中的要求是去求划分的子序列的最大值尽量小,最大值最小化,如果从划分的角度看,无法获得好的思路,我们可以从值得角度考虑,所要求的最小的最大值必定是从[amax,sum(总和)]中取得的,那么我们可以二分法的方式猜测一个数字,看它是否满足要求,如果满足要求,我们可

UVA 714 Copying Books

题意: 要抄N本书,编号为1,2,3...N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的.每个抄写员的速度是相同的,求所有书抄完所用的最少时间的分配方案. 分析: 这个题以前做过.就是先二分出来,最大的区间最小值.然后一重循环查找输出/就好 代码: #include <iostream>#include <cstring>#include <cstdio>#include <al

714 - Copying Books——[贪心、二分查找]

Before the invention of book-printing, it was very hard to make a copy of a book. All the contents had to be re-written by hand by so called scribers. The scriber had been given a book and after several months he finished its copy. One of the most fa

714 - Copying Books(二分)

该题是所谓"最大值尽量小"的典型代表,方法就是用二分猜这个最值,判断函数就是从前向后扫,尽量向后划,如果最后划出的组数比k小,那么显然可以划成k组. 代码如下: #include<bits/stdc++.h> using namespace std; typedef long long ll; int T,n,k,a[505]; bool P(int m) { int ans=0,cnt=1; for(int i=0;i<n;i++) { ans+=a[i]; if(