NOI2019模拟赛 T1
by Wearry
题目描述
牛油果是一种神秘的水果,其具有一个坚固程度 x ≥ 0 x ≥ 0 x≥0:即从高度不超过 x x x 米的地方掉下来都不会受损,否则就会破碎。现在有 n n n 个牛油果可以用来做实验,如果某个牛油果在一次实验的过程破碎了就不能继续做实验,否则就可以继续拿来做实验。假设给出的牛油果坚固程度相同,且已知它们的坚固程度不超过 m m m,现在要求最坏情况下最少做多少次实验可以得知它们的坚固程度。多组数据。
数据规模:
对于
10
%
10\%
10% 的数据,
n
,
m
,
T
≤
10
n,m,T\le 10
n,m,T≤10
对于
30
%
30\%
30% 的数据,
n
,
m
,
T
≤
50
n,m,T\le 50
n,m,T≤50
对于
60
%
60\%
60% 的数据,
n
,
m
,
T
≤
500
n,m,T\le 500
n,m,T≤500
对于
100
%
100\%
100% 的数据,
n
,
m
,
T
≤
5000
n,m,T\le 5000
n,m,T≤5000
题解
签到题。
考试时花了半个小时才想到 60 60 60 分做法。
考虑 dp.
设 f [ i ] [ j ] f[i][j] f[i][j] 为有 i i i 个牛油果,坚固程度小于等于 j j j 时,最坏情况下最少做实验的次数。
分类讨论,若在高度为 k k k 的位置扔下牛油果烂或者不烂。
若在高度为 k k k 的位置扔下牛油果烂了,那么答案为 f [ i − 1 ] [ k − 1 ] + 1 f[i-1][k-1]+1 f[i−1][k−1]+1,因为剩下的 i − 1 i-1 i−1 个牛油果,而坚固程度 x x x 必定小于 k k k,也就是小于等于 k − 1 k-1 k−1.
若在高度为 k k k 的位置扔下牛油果没烂,那么答案为 f [ i ] [ j − k ] + 1 f[i][j-k]+1 f[i][j−k]+1,因为还有 i i i 个牛油果,而范围变成了 k ≤ x ≤ j k\le x\le j k≤x≤j,范围大小为 j − k j-k j−k.
所以得 f [ i ] [ j ] = min k = 1 j ( max ( f [ i − 1 ] [ k − 1 ] , f [ i ] [ j − k ] ) + 1 ) f[i][j]=\min\limits_{k=1}^{j}(\max(f[i-1][k-1],f[i][j-k])+1) f[i][j]=k=1minj(max(f[i−1][k−1],f[i][j−k])+1).
这样的时间复杂度为 O ( n m 2 ) O(nm^2) O(nm2). 这是我考试时的做法,可得 60 60 60 分。
其实当 n n n 大于 14 14 14 时可以当成 14 14 14 算。
若不考虑 n n n 的限制,最多只需要扔 log m \log m logm 次牛油果就能得出结果。
所以当 n n n 大于 log 5000 ≤ 14 \log 5000\le 14 log5000≤14 的时候,我们只需要最多 14 14 14 个牛油果就能得出答案。
那么 f [ i ] [ j ] f[i][j] f[i][j] 的 i i i 只用枚举到 14 14 14 就可以了。
时间复杂度 O ( m 2 log m ) O(m^2\log m) O(m2logm).
话说好像直接输出
log
m
\log m
logm 能过。czn 和 szt 使用
log
m
\log m
logm 乱搞通过了本题,并且复杂度爆踩标程。样例是用哪只脚造的啊。我太菜了,只会
60
60
60 分 dp.
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
int T, n, m, f[N][N];
void init() {
memset(f, 0x3f, sizeof(f));
for (int i = 1; i < N; i++) f[i][0] = 0, f[i][1] = 1, f[1][i] = i;
for (int i = 2; i <= 14; i++)
for (int j = 1; j < N; j++)
for (int k = 1; k <= j; k++)
f[i][j] = min(f[i][j], max(f[i - 1][k - 1], f[i][j - k]) + 1);
}
int main() {
init();
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m), n = min(n, 14);
printf("%d\n", f[n][m]);
}
return 0;
}