bzoj4428[Nwerc2015]Debugging调试 数论+记忆化搜索

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4428[Nwerc2015]Debugging调试 数论+记忆化搜索相关的知识,希望对你有一定的参考价值。

题目描述

一个 $n$ 行的代码出了bug,每行都可能会产生这个bug。你要通过输出调试,在其中加入printf来判断bug出现的位置。运行一次程序的时间为 $r$ ,加入一条printf的时间为 $p$ ,求最坏情况下调出程序的最短时间。

输入

输入包括一行三个整数:
n(1≤n≤10^6),代码行的数目;
r(1≤r≤10^9),编译和运行程序直到它崩溃的时间量;
p(1≤p≤10^9),增加单个的printf行所花费的时间。

输出

输出的最坏情况使用最优策略找到崩溃行的时间。

样例输入

16 1 10

样例输出

44


题解

数论+记忆化搜索

看题第一眼dp,设 $f[i]$ 表示 $i$ 行代码最坏情况下的最短时间。那么枚举添加的printf语句数,可以得出dp方程:$f[i]=f[\lceil\frac i{j+1}\rceil]+jp+r$ 。

考虑优化:$\lceil\frac ni\rceil$ 和下取整一样最多只有 $O(\sqrt n)$ 个值。方法:从大到小枚举 $i$ ,令 $last=\lceil\frac n{\lceil\frac ni\rceil}\rceil$ ,则 $last$ 就是最后一个满足 $\lceil\frac nj\rceil=\lceil\frac ni\rceil$ 的 $j$ 。由于要让方程中的 $j$ 尽量小,因此使用 $last$ 转移。下一次令 $i=last-1$ 即可。

但是这样 $O(n\sqrt n)$ 的时间复杂度还是过不了,考虑进一步优化:只有一个询问,因此无需知道大多数无用的 $f$ 值。使用记忆化搜索,这样更新的结果就只有 $f[\lceil\frac ni\rceil]$ 了。

使用微积分知识可以证得时间复杂度为 $O(n^{\frac 34})$ (和杜教筛相同)

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll f[1000010] , r , p;
inline int cdiv(int x , int y)
{
	return (x + y - 1) / y;
}
ll solve(int n)
{
	if(n == 1) return 0;
	if(f[n]) return f[n];
	int i , j;
	f[n] = 1ll << 62;
	for(i = n ; i != 1 ; i = j - 1)
		j = cdiv(n , cdiv(n , i)) , f[n] = min(f[n] , solve(cdiv(n , i)) + (j - 1) * p + r);
	return f[n];
}
int main()
{
	int n;
	scanf("%d%lld%lld" , &n , &r , &p);
	printf("%lld\n" , solve(n));
	return 0;
}

 

 

以上是关于bzoj4428[Nwerc2015]Debugging调试 数论+记忆化搜索的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4428[Nwerc2015]Debugging调试 数论+记忆化搜索

bzoj 4430: [Nwerc2015]Guessing Camels赌骆驼

BZOJ4429[Nwerc2015] Elementary Math小学数学 最大流

[bzoj4429] [Nwerc2015] Elementary Math小学数学

bzoj4430 [Nwerc2015]Guessing Camels赌骆驼

BZOJ4430: [Nwerc2015]Guessing Camels赌骆驼