题目描述
Jimmy有n支蜡烛。他把这些蜡烛排成了一排,从左往右的编号为1~n。经过无数次的实验后,他发现每支蜡烛有一个属性a[i],当第i支蜡烛左边(即第i-1支,当时的风向比较奇妙)的蜡烛被点亮后,经过a[i]的时间第i支蜡烛也会点亮。
Jimmy一开始先任意点m支蜡烛(不需要消耗时间),他想知道至少需要多少时间才能使得n支蜡烛全部被点亮。
输入
从文件 d.in
中读入数据。
第一行两个整数n,m。
第二行n个空格分开的整数a[i]。
输出
输出到文件 d.out
中。
一行一个整数表示所有蜡烛都亮的最小时间。
样例输入
5 3 1 2 2 1 5
样例输出
2
数据范围限制
对于20%的数据:n,m<=10。
对于50%的数据:n,m<=3000
对于100%的数据:1<=m<=n<=10^5,1<=a[i]<=10^9。
样例解释
点燃1、3、5根蜡烛,需要2的时间烧到第二根,1的时间烧到第四根,最小时间为2。
这题我们可以用二分进行一个最短时间的一个计算
Coding~~~
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 20;
int n, m;
int a[N], sum;
void dg(int l, int r) { /*枚举时间范围*/
int mid = (l + r) / 2;
int cnt = 1/*点燃的蜡烛的数量*/, t = 0/*目前最小时间*/;
for (int i = 2; i <= n; i++) {
t += a[i];//将时间+目前蜡烛点燃的时间
if (t > mid) {//如果t大于目前的时间最小值,必须点燃这一个蜡烛
if (cnt < m) cnt++, t = 0;//点蜡烛
else {
if (r == l) return ;//如果时间重合,返回上一层
else if (l + 1 == r) dg(mid + 1, r);//防止mid卡循环,例:l=1,r=2,mid=1会卡死循
else dg(mid, r);//没问题,继续分治
return ;//返回
}
}
}
sum = mid;//将答案储存
if (l == r)
return ;//同上
dg(l, mid - 1);//继续分治
}
main() {
freopen("d.in", "r", stdin);
freopen("d.out", "w", stdout);
cin >> n/*蜡烛编号*/ >> m/*可以点亮m个蜡烛*/;
for (int i = 1; i <= n; i++)
cin >> a[i]/*输入*/, sum += a[i]/*使用sum进行计数*/;
dg(1, sum - a[1]/*第一个蜡烛必点,所以sum-a[1]*/);
cout << sum;
return 0;
}