【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;
}

原文地址:https://www.cnblogs.com/GXZlegend/p/8135724.html

时间: 2024-10-05 02:05:44

【bzoj4428】[Nwerc2015]Debugging调试 数论+记忆化搜索的相关文章

BZOJ4428 : [Nwerc2015]Debugging调试

设$f[i]$为最优策略下调试$i$行代码的时间,则: $f[1]=0$ $f[i]=\min((j-1)\times p+f[\lceil\frac{i}{j}\rceil])+r$ 意义为枚举printf语句的个数,然后尽量均分,并假设坏点在最大的段落里. 考虑记忆化搜索,注意到对于每个$i$来说只有$O(\sqrt{i})$个决策有用,所以时间复杂度为$O(n^\frac{3}{4})$. #include<cstdio> typedef long long ll; int n,r,p,

uva 10581 - Partitioning for fun and profit(记忆化搜索+数论)

题目链接:uva 10581 - Partitioning for fun and profit 题目大意:给定m,n,k,将m分解成n份,然后按照每份的个数排定字典序,并且划分时要求ai?1≤ai,然后输出字典序排在k位的划分方法. 解题思路:因为有ai?1≤ai的条件,所以先记忆化搜索处理出组合情况dp[i][j][s]表示第i位为j,并且剩余的未划分数为s的总数为dp[i][j][s],然后就是枚举每一位上的值,判断序列的位置即可. #include <cstdio> #include

bzoj 4428: [Nwerc2015]Debugging调试

4428: [Nwerc2015]Debugging调试 Description Your fancy debugger will not help you in this matter. There are many ways in which code can produce different behavior between debug and release builds, and when this happens, one may have to resort to more pr

HDU5115 Dire Wolf 区间DP 记忆化搜索

题意:举个例子,就跟DOTA里的狼BB一样,自身有攻击力,还有光环可以提升同伴的攻击力,狼站成一排,光环只能提供给相邻的狼,打掉一直狼需要打一下,同时它也会打一下,这样你的扣血量其实就等于该狼的攻击力 方程很好想,dp[i][j]代表 打掉区间[i,j]内的狼所需最少血量,这里是闭区间,后来看到是200*200 ,那么就懒得去想方程转移了,直接记忆化搜索就可以了,注意点是 一个狼被宰了,它相邻两边的两只狼攻击力会减少,所以搜索过程 分区间搜索时边界要设定好,一开始没弄好 结果 案例一直没跑出来,

[hihocoder 1033]交错和 数位dp/记忆化搜索

#1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0,?a1,?...,?an?-?1,定义交错和函数: f(x)?=?a0?-?a1?+?a2?-?...?+?(?-?1)n?-?1an?-?1 例如: f(3214567)?=?3?-?2?+?1?-?4?+?5?-?6?+?7?=?4 给定 输入 输入数据仅一行包含三个整数,l,?r,?k(0?≤?l?≤?r?≤?1018,?|k|

HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数. 题解1(LCS): 很神奇的做法. 先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数. 然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可. 所以答案是:s.size()-LCS(s,rev(s)) 另外,求LCS时只会用到lcs[i-

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

poj 1579(动态规划初探之记忆化搜索)

Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17843   Accepted: 9112 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b

记忆化搜索,FatMouse and Cheese

1.从gird[0][0]出发,每次的方向搜索一下,每次步数搜索一下 for(i=0; i<4; i++) { for(j=1; j<=k; j++) { int tx=x+d[i][0]*j; int ty=y+d[i][1]*j; if(tx>=0&&tx<n&&ty>=0&&ty<n&&grid[x][y]<grid[tx][ty]) { int temp=memSearch(tx,ty); i