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