我正在尝试解决下面描述的问题,
给定f(0)和k的值,它们是整数。
我需要找到f(T)的值。其中T <= 10 10
递归函数是,
f(n) = 2*f(n-1) , if 4*f(n-1) <=k
k - ( 2*f(n-1) ) , if 4*f(n-1) > k
我的努力,
#include<iostream>
using namespace std;
int main(){
long k,f0,i;
cin>>k>>f0;
long operation ;
cin>>operation;
long answer=f0;
for(i=1;i<=operation;i++){
answer=(4*answer <= k )?(2*answer):(k-(2*answer));
}
cout<<answer;
return 0;
}
我的代码给了我正确的答案。但是,在最坏的情况下,代码将运行10 10 时间,这给了我超时限制。我需要更有效的解决方案来解决这个问题请帮我。我不知道正确的算法。
答案 0 :(得分:1)
如果2f(0)&lt; k然后你可以在O(log n)时间内计算这个函数(通过用模k求平方来求幂)。
r = f(0) * 2^n mod k
return 2 * r >= k ? k - r : r
你可以通过归纳来证明这一点。归纳假设是0 <= f(n)<0。 k / 2,并且上面的代码片段计算f(n)。
这是一个Python程序,它检查随机测试用例,比较天真的实现(f
)和优化的实现(g
)。
def f(n, k, z):
r = z
for _ in xrange(n):
if 4*r <= k:
r = 2 * r
else:
r = k - 2 * r
return r
def g(n, k, z):
r = (z * pow(2, n, k)) % k
if 2 * r >= k:
r = k - r
return r
import random
errs = 0
while errs < 20:
k = random.randrange(100, 10000000)
n = random.randrange(100000)
z = random.randrange(k//2)
a1 = f(n, k, z)
a2 = g(n, k, z)
if a1 != a2:
print n, k, z, a1, a2
errs += 1
print '.',
答案 1 :(得分:0)
你能在编程和计算之前使用甲基化解决方案吗?
实际上,
f(n)= f0 * 2 ^(n-1),如果f(n-1)* 4&lt; = k
k-f0 * 2 ^(n-1),如果f(n-1)* 4> ķ
因此,你的代码会这样写:
condition = f0*pow(2, operation-2)
answer = condition*4 =< k? condition*2: k - condition*2
答案 2 :(得分:0)
对于一个简单的循环,你的答案看起来很紧;一个人可以使用answer<<2
代替4*answer
进行优化,answer<<1
代替2*answer
,但很可能你的编译器已经这样做了。如果你正在用这个来节省时间,可能有必要以某种方式减少循环本身。
我无法弄清楚@Shannon想要的数学模式,但我认为我们可以利用这个函数迟早会循环的事实。如果周期足够短,那么我们可以通过在周期中的同一点获得答案来缩短循环。
因此,让我们以Brent's algorithm的形式获得一些循环检测设备,看看我们是否可以将循环切割到合理的水平。
def brent(f, x0):
# main phase: search successive powers of two
power = lam = 1
tortoise = x0
hare = f(x0) # f(x0) is the element/node next to x0.
while tortoise != hare:
if power == lam: # time to start a new power of two?
tortoise = hare
power *= 2
lam = 0
hare = f(hare)
lam += 1
# Find the position of the first repetition of length λ
mu = 0
tortoise = hare = x0
for i in range(lam):
# range(lam) produces a list with the values 0, 1, ... , lam-1
hare = f(hare)
# The distance between the hare and tortoise is now λ.
# Next, the hare and tortoise move at same speed until they agree
while tortoise != hare:
tortoise = f(tortoise)
hare = f(hare)
mu += 1
return lam, mu
f0 = 2
k = 198779
t = 10000000000
def f(x):
if 4 * x <= k:
return 2 * x
else:
return k - 2 * x
lam, mu = brent(f, f0)
t2 = t
if t >= mu + lam: # if T is past the cycle's first loop,
t2 = (t - mu) % lam + mu # find the equivalent place in the first loop
x = f0
for i in range(t2):
x = f(x)
print("Cycle start: %d; length: %d" % (mu, lam))
print("Equivalent result at index: %d" % t2)
print("Loop iterations skipped: %d" % (t - t2))
print("Result: %d" % x)
与其他提出的答案相反,这种方法实际上可以使用备忘录数组来加速进程,因为函数的开始实际上是多次计算的(特别是在brent
内),或者它可能无关紧要,取决于周期有多大。
答案 3 :(得分:0)
您提出的算法已经有O(n)。 为了提出更有效的算法,我们没有太多的方向可以解决。我们有一些典型的选择
1.减去线性项的系数(但我怀疑它会在这种情况下产生影响
2.更改为O(Logn)(通常使用某种分治技巧)
3.改为O(1)
在这种情况下,我们可以做最后一个。 递归函数是分段函数
f(n) = 2*f(n-1) , if 4*f(n-1) <=k
k - ( 2*f(n-1) ) , if 4*f(n-1) > k
让我们按案件处理:
情况1:如果4 * f(n-1)&lt; = k(1)(假设起始指数为零) 这是一个显而易见的几何系列
a_n = 2 * a_n-1
因此,请使用公式
Sn = 2 ^(n-1) f(0)----()
情况2:如果4 * f(n-1)> k(2),我们有
a_n = -2a_n-1 + k
假设a_j是序列中满足条件(2)的元素
在公式的_1中嵌套子,您将获得等式
an = k -2k + 4k -8k ... +( - 2)^(n-j)* a_j
k -2k 4k -8 ...是另一个gemo系列
Sn = k *(1-2 ^(n-j))/(1-2)---具有起始值k和比率= -2的gemo级数和公式
因此,我们在案例2中有一个公式
an = k *(1-2 ^(n-j))/(1-2)+( - 2)^(n-j)* a_j ----(**)
我们所有离开去找到一个只是不满足条件(1)并满足(2)
的aj这可以使用我们对案例1的公式再次在恒定时间内获得:
找到n,使得4 * an = 4 * Sn = 4 * 2 ^(n-1)* f(0) 求解n:4 * 2 ^(n-1)* f(0)= k,如果n不是整数,取n的上限
在我第一次尝试解决这个问题时,我错误地假设序列的值是单调递增的,但实际上序列可能会在案例1和案例2之间跳转。因此,可能没有常数算法来解决问题
但是,我们可以使用上面的结果来跳过迭代更新的复杂性。
整体算法看起来像:
以T,K和f(0)
开头计算n使用(*)或(**)
进行条件切换用f(n)更新f(0),更新T - n
重复
在T-n = 0时终止(最后一次迭代可能超过计算导致T-n <0,因此,如果发生这种情况,你需要稍微回过头来)
答案 4 :(得分:-2)
创建可存储结果的地图。在找到f(n)之前检查该地图,如果解决方案已经存在或不存在。 如果存在,请使用该解决方案。 否则找到它,存储它以备将来使用。
对于C ++:
定义:
map<long,long>result;
插入:
result[key]=value
访问:
value=result[key];
检查:
map<long,long>::iterator it=result.find(key);
if(it==result.end())
{
//key was not found, find the solution and insert into result
}
else
{
return result[key];
}
使用上述技术以获得更好的解决方案。