使用K个字母查找长度为N的回文总数,以使长度为2到N-1的任何前缀都不是回文。
尝试K*((K-1)^(Math.ceil((N-2)/2)))
第一位可以容纳K个字母。第二个K-1,除了第一个。第三名也是如此。
由于我们需要用字母填充的一半位置的其余部分将遵循相同的条件以使其成为回文。但这不是正确的解决方案。
答案 0 :(得分:1)
表示M = \ceil{N / 2}
。该公式取决于一个简单的观察结果,即如果长度为N
的回文报文的回文前缀为长度小于2
的非平凡(即长度至少为N
),则其回文前缀为长度不超过M
的非平凡回文前缀。
如果我们用f(n)
表示长度为n
的 good 回文数(没有回文前缀长度为2
和{{1}之间的回文数) }),我们可以通过从回文总数中减去坏回文数的数量来计算n - 1
。根据上面的观察,每个不良回文都有一个{em>最小非平凡回文前缀,其长度f(N)
在K^M
和L
(包括)之间,这必须是一个好回文。每个2
都有M
这样的前缀,并且它们中的任何一个都可以通过f(L)
的方式扩展为长度为L
的回文,所以
N
答案 1 :(得分:0)
我编写了一个Python脚本来检查Łukasz's answer中是否有N
和K
的较小值。
import functools
import itertools
import string
@functools.lru_cache()
def f(N, K):
if N == 2:
return K
M = (N + 1)//2
return K**M - sum(K**(M - L) * f(L, K) for L in range(2, M+1))
def is_palindrome(s):
return s[:(len(s) + 1)//2] == s[len(s)//2:][::-1]
def brutal_f(N, K):
alphabet = string.ascii_lowercase[:K]
ret = 0
for t in itertools.product(alphabet, repeat=N):
s = "".join(t)
if is_palindrome(s) and not any(is_palindrome(s[:i]) for i in range(2, N)):
ret += 1
return ret
print(all(
f(N, K) == brutal_f(N, K)
for N in range(12)
for K in range(4)
))