冉文的烦恼——解题报告

冉文的烦恼

【问题描述】

冉文是个粗心的人,经常不小心把垃圾丢到地上。艾教实在没办法,只好派了m个学生,去捡冉文走过路上的垃圾。

假设冉文走过的路线是一条直线,每个位置分别是1..n,每个位置上垃圾的个数是ai。所有学生起始位置都在0,每秒钟,他们有两种选择:

1.向右走一步。

2.捡起一个地上的垃圾。

现在我们的问题是:要捡起冉文的所有垃圾,最少需要多少秒?

【输入格式】

第一行输入两个正整数n,m,如题目所述。

第二行输入n个非负整数ai,代表每个位置的垃圾个数。ai<=10^9

【输出格式】

一个数字,表示最少的时间。

【输入样例】

3 2

1 0 2

【输出样例】

5

解释:第一个学生走到3,然后捡2个垃圾,共花费时间5,第二个学生走到1,捡1个垃圾,共花费时间2。

【数据范围与约定】

对于30%的数据,m=1。

对于另30%的数据,m=2,垃圾总个数<=21。

对于100%的数据,n,m<=100000

【个人想法】

二分答案,因为每个点都小于10^9,所以下界0,上界为n*10^9

然后贪心(算是吧)

一个人先从起点往后捡,然后自己时间完了的时候让下一个人继续刚才的位置再往后捡,如果超过m个人时就不行,return,如果至尾也都没超m个人,就行。

【题解代码】

第一个是自己写的,交上去后re,结果是a[1000005]写成了a[100005]...

改了后90分,因为上界应该是1000000000*n,我又少数了个0,成了100000000*n。。。

有点想死。。。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
ll n,m;
ll a[1000005];
bool can(ll lim)
{
	//cout<<lim<<"????"<<endl;
	ll op=lim;
	ll kl=1;
	ll k=0;
	for(ll i=1;i<=n;i++)
	{
		op-=1;
		if(op>=a[i])
			op-=a[i];
		else
		{
			k=a[i]-op;
			op=0;
		}
		if(i==n&&k<=0)
			break;
		if(op==0)
		{
			kl++;
			op=lim-i-k;
		}
		while(op<0)
		{
			kl++;
			op+=lim-i;
			if(lim-i<=0)
			return 0;
		}
		k=0;
	}
	if(kl<=m)
		return 1;
	else
		return 0;
}
int main()
{
	freopen("ranwen.in","r",stdin);
	freopen("ranwen.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(ll i=n;i>=1;i--)
	{
		if(a[i]==0)
		{
			n--;
		}
		else
		{
			break;
		}
	}
	ll l=0,r=1000000000*n;
	while(l+1<r)
	{
		ll mid=(l+r)/2;
		if(can(mid)==1)
			r=mid;
		else
			l=mid+1;
	}
	if(can(r-1)&&r>0)
		r-=1;
	cout<<r; 
 } 

第二个是教练给的
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;

long long int n, m, a[100005];

bool check(long long int t){
    long long int um = m, extra = 0;
    for (int i=0;i<n;i++){
        if (um >= a[i]/t) um -= a[i]/t;
        else return false;
        if (extra >= a[i]%t) extra -= a[i]%t;
        else if (um){
            extra += t - a[i]%t;
            um--;
        }
        else return false;
        if (!--t){
            for(int j=i+1;j<n;j++)
                if (a[j])return false;
            return true;
        }
        if (extra)extra--;
    }
    return true;
}

int main(int argc,char **argv)
{
    // argv[2]鏄枃浠跺悕
    freopen(argv[2],"r",stdin);
    char ch[20]="ranwen0.out";
    ch[6]=argv[2][6];
    freopen(ch,"w",stdout);

    scanf("%lld%lld",&n,&m);
    for (int i=0;i<n;i++)
        scanf("%lld",a+i);
    long long int ub = 2000000000000000, lb = 0;
    while (ub-lb-1){
        long long int mid = (ub+lb)/2;
        if (check(mid)) ub = mid;
        else lb = mid;
    }
    cout<<ub+1<<endl;
}
后面的这个应该靠谱些。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值