题目:一本书要分给n个人打理,问如何分割使的最大值最小,并且要使得前面的人的最小
我的最初做法:
枚举答案,用for循环,再在递归里再去枚举答案。
但是wa了,我还未知原因。
看了网上题解之后
发现它是用二分的,枚举答案,不如用二分缩小答案范围更快,
而对于要使越前面的人分到的越小,它是很取巧的,如果要分n部分,但是只分了n-2,直接从前面往后面分,没有”/“的元素就是直接价格“/”。
总体思路:
猜测答案,验证答案对否(方法是直接看拆的的分数符合要求否),再不停的用二分猜测答案验证答案,最后标记输出。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=600;
ll m,n,sum[maxn],all[maxn];
bool is_ok(ll a)
{
ll now=a;
int th=0,time=0;
while(th<=m)
{
int k=upper_bound(sum+1,sum+m+1,now)-sum-1;
time++;
now=sum[k]+a;
if(k==m)
{
if(time<=n)return 1;
return 0;
}
if(k==th)return 0;
th=k;
}
}
ll solve()
{
ll lef=sum[m]/n,rig=sum[m];
while(lef<rig)
{
ll ans=lef+(rig-lef)/2;
if(is_ok(ans))rig=ans;
else lef=ans+1;
}
return lef;
}
void print(ll ans)
{
ll biao[maxn];
memset(biao,0,sizeof(biao));
ll tot;
int time=0;
for(int i=m;i>=1;)
{
tot=0;
while(tot+all[i]<=ans)
{
tot+=all[i--];
}
biao[i]=1;
time++;
}
int dt=1;
while(time!=n)
{
if(!biao[dt]){biao[dt]=1;time++;}
dt++;
}
for(int i=1;i<=m;i++)
{
printf("%lld%s",all[i],i==m?"\n":" ");
if(biao[i])printf("/ ");
}
}
int main(void)
{
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%lld %lld",&m,&n);
sum[0]=0;
for(int i=1;i<=m;i++)
{
scanf("%lld",&all[i]);
sum[i]=sum[i-1]+all[i];
}
ll ans=solve();
print(ans);
}}