小K的花园种着n颗竹子(竹子是一种茎部中空并且长得又高又快的热带植物)。此时,花园中第i颗竹子的高度是hi米,并且在每天结束的时候它生长ai米。
实际上,小K十分讨厌这些竹子。他曾经试图去砍光它们,但由于竹子的茎部太坚固而失败了,然而,小K制作了魔法锤使这些竹子只能在地面上生长。
由于魔法力量有限,他每天最多能使用K次魔法锤。每次他使用魔法锤敲击竹子,竹子的高度就会减少p米。通过这次改变,如果竹子的高度变为负数,那它转而会变为0米(但它不会消失)。换言之,如果一颗被魔法锤敲击的竹子的高度是h,那它的新高度将会是max(0, h - p)米。我们可以在一天中多次敲击同一颗竹子。
小K将会从今天开始和这些竹子抗战m天。他的目标是在m天后使其中最高的竹子的高度最小化(即,“小K敲击竹子,然后竹子生长”的m次迭代)。找出m天后,最高的竹子的高度的最小可能值。
Input
输入的第一行包含四个以空格隔开的整数n,m和p(1 ≤ n ≤ 10^5 ,1 ≤ m ≤ 5000, 1 ≤k≤ 10, 1 ≤ p ≤ 10^9)。它们分别表示小K 花园中的竹子数,小K抗战的持续天数,每天小K能敲击竹子的最多次数和魔法锤的力量。 接下来n行描述了竹子的特性,第i行(1 ≤ i ≤ n) 包含两个以空格隔开的整数hi和ai,(0 ≤ hi ≤ 10^9, 1 ≤ ai ≤ 10^9),分别表示第i颗竹子的初始高度和生长速率。
Output
输出m天后,最高的竹子的高度的最小可能值。
Input示例
3 1 2 5 10 10 10 10 15 2
Output示例
17
这个题对着codeforces上的题解一直看不太懂。。。主要就是这一块:
ll target = (grow[i] - x) % p ? (grow[i] - x) % p : p;
while (target <= grow[i] - x)
{
if (target <= h[i])
{
t[0]++;
}
else if((ll)ceil((double)(target - h[i]) / (double)v[i]) > (m - 1))
{
return 0;
}
else
{
t[(ll)ceil((double)(target - h[i]) / (double)v[i])]++;
}
target += p;
}
想了一下午这块的代码应该怎么搞,发现就是求x*v[i]+h[i]>=target target是要砍掉的长度,我们希望只要
x*v[i]+h[i]>=target 刚刚满足的那一天x,就把竹子砍掉。简单来说,就是这个魔法在满足条件的情况下尽量提前使用。搞懂了这块,感觉这个题二分顺畅了好多~。
代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3fffffff
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
ll n, m, k, p, le, mid, ri;
ll h[maxn], v[maxn], grow[maxn], t[5005];
void input()
{
int i;
scanf("%I64d%I64d%I64d%I64d", &n, &m, &k, &p);
ri = 0;
for (i = 1; i <= n; i++)
{
scanf("%I64d%I64d", &h[i], &v[i]);
grow[i] = h[i] + v[i] * m;
ri = max(ri, grow[i]);
}
}
bool check(ll x)
{
ll i, num = 0;
for (i = 1; i <= n; i++)
{
num += max(0LL, (ll)ceil((double)(grow[i] - x) / (double)p));
}
if (num > m*k)
{
return 0;
}
memset(t, 0, sizeof(t));
for (i = 1; i <= n; i++)
{
if (grow[i] <= x)continue;
ll target = (grow[i] - x) % p ? (grow[i] - x) % p : p;
while (target <= grow[i] - x)
{
if (target <= h[i])
{
t[0]++;
}
else if((ll)ceil((double)(target - h[i]) / (double)v[i]) > (m - 1))
{
return 0;
}
else
{
t[(ll)ceil((double)(target - h[i]) / (double)v[i])]++;
}
target += p;
}
}
ll rest = 0;
for (i = 0; i < m; i++)
{
rest += t[i];
rest = max(0LL, rest - k);
}
return rest == 0;
}
void solve()
{
le = 0; ri++;
while (le < ri)
{
mid = (le + ri) / 2;
if (check(mid))
{
ri = mid;
}
else
{
le = mid + 1;
}
}
printf("%I64d", ri);
}
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
input();
solve();
//system("pause");
return 0;
}