大致题意:告诉你你的存款余额在一个区间内,然后每次你可以猜一个数字,如果余额大于等于你猜的数字,那么你可以取走这些钱并且代价为a,否则为代不能取走且价为b。你可以多次重复这个动作,直到你能够确定你初始时的总共有多少钱。现在问你,最少花费多少的代价能够知道你初始时的账户余额。
这题有点像二分的意思,如果a和b相等,那么显然按照二分的策略即是最优。考虑到这一点,我们显然可以发现,这题的答案与具体区间在哪无关,只与区间大小有关。然后,可以分为两类,一类是左端点为0的,相当于左端点可以不考虑,另一类是左端点不为0的。正如之前所说的,如果是二分的话,是选择中间点作为分界,现在不是二分,我们就得考虑枚举这个分界点。我们考虑dp,令dp[i][0]表示跨度为i的区间左端点为0时最少的花费,dp[i][1]表示跨度为i且左端点不为0时最少的花费。很容易有转移方程:
具体表示枚举中间的分界点j,如果正确答案在j左边的时候代价为dp[j-1][0]+b,如果在右边的时候代价为dp[i-j][0]+a,取二者中大的表示最坏清空。然而,直接转移复杂度是O(N^2)的,本题这么做会TLE,所以要考虑进行优化。
显然,区间跨度越大,花费的代价也就越大,dp[i][0]和dp[i][1]是具有单调性的。然后考虑这个转移方程,取前后两部分大的那个,可以预见,代价随着决策点j从左往右移动先变小后变大。所以,我们可以考虑直接对这个转移方程进行三分,找到中间的最小决策。但是,用上三分理论复杂度可以过去,不过我写的确实TLE了,当然可能是我写残了。
于是,继续考虑转移方程,可以发现,我们转移的时候,随着区间跨度的变大,最优决策点也是单调不降的。因此我们可以利用这个性质把时间复杂度变成线性的。初始时决策点就在最左边,然后每次计算出答案后尝试移动决策点看是否会更优,如果更优那么往右移动。如此,时间复杂度均摊下来就是O(N)的,实际运行速度也是非常的块。具体见代码: