题目链接: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;
}

 

posted on 2015-08-16 14:37  中子星  阅读(326)  评论(0编辑  收藏  举报