确定(x ^ 2 + x + 1)^ n中的x ^ m项的系数是偶数或奇数

时间:2017-04-29 09:46:48

标签: algorithm math algebra number-theory mod

对于给定的整数nm,确定x^m(x^2+x+1)^n项的系数是偶数还是奇数?

例如,如果n = 3且m = 4,(x^2+x+1)^3 = x^6 + 3x^5 + [[6x^4]] + 7x^3 + 6x^2 + 3x + 1,则x^4项的系数为6(=偶数)。

nm与10 ^ 12一样大,我想在几秒钟内计算,因此您无法在线性时间内计算。

你有任何有效的算法吗?

4 个答案:

答案 0 :(得分:6)

首先要注意的是,如果只对x ^ m的系数是奇数还是偶数感兴趣,可以将多项式的系数视为有限域F2的元素。

注意(1+x+x^2)^2 = (1+x^2+x^4) mod 2因为交叉条款都是均匀的。实际上,如果n是2的幂,那么(1+x+x^2)^n = (1 + x^n + x^2n) mod 2

对于一般n,将其写为2的幂之和(即二进制)。

n = (2^a1 + 2^a2 + 2^a3 + ... + 2^ak).

然后将对应于2的每个幂的幂相乘:

(1+x+x^2)^n = (1+x^(2^a1)+x^(2^(a1+1))) * ((1+x^(2^a2)+x^(2^(a2+1))) * ...

此产品中的每个术语现在只有3个因子,如果n以10 ^ 12为界,则最多有35个或36个。所以很容易将它们相乘。

这是一些执行此操作的Python代码:

# poly_times computes the product of polynomials
# p and q over the field F2. They are each
# represented by a set of non-zero coefficients.
# For example set([0, 2, 5]) corresponds to x^0 + x^2 + x^5.
def poly_times(p, q):
    result = set()
    for i in p:
        for j in q:
            if i+j in result:
                result.remove(i+j)
            else:
                result.add(i+j)
    return result

# Return the coefficient of x^m in (1+x+x^2)^n.
def coeff(n, m):
    prod = set([0])
    i = 0
    while n:
        if n % 2:
            prod = poly_times(prod, [0, 2**i, 2**(i+1)])
        i += 1
        n >>= 1
    return 1 if m in prod else 0

for m in xrange(10):
    print m, coeff(3, m)

print coeff(1947248745, 1947248745034)    

优化

对于设置了大量位的n,当n接近10 ^ 12时,这会变得太慢。

但是,通过将多项式幂分成两部分,然后在最后一步中找到m的系数,而不是通过进行完全多项式乘法,而是通过计算系数对,可以大大加快速度。每个部分总和为m。这是优化的coeff

# poly_times computes the product of polynomials
# p and q over the field F2. They are each
# represented by a set of non-zero coefficients.
# For example set([0, 2, 5]) corresponds to x^0 + x^2 + x^5.
# Coefficients larger than m are discarded.
def poly_times(p, q, m):
    result = set()
    for i in p:
        for j in q:
            if i + j > m:
                continue
            if i+j in result:
                result.remove(i+j)
            else:
                result.add(i+j)
    return result

# Return the coefficient of x^m in (1+x+x^2)^n.
def coeff(n, m):
    if m > 2*n: return 0
    prod = [set([0]), set([0])]
    i = 0
    while n:
        if n % 2:
            prod[i//20] = poly_times(prod[i//20], [0, 2**i, 2**(i+1)], m)
        i += 1
        n >>= 1
    s = 0
    for x in prod[0]:
        s += m-x in prod[1]
    return s % 2

for m in xrange(10):
    print m, coeff(3, m)

print coeff(0xffffffffff, 0xffffffffff)

请注意,这可以在几秒钟内计算coeff(0xffffffffff, 0xffffffffff)0xffffffffff大于10 ** 12。

答案 1 :(得分:4)

是,输入中位数的线性时间。

所讨论的系数是三项式系数T(n, m)。对于二项式系数,我们将使用Lucas's theorem;让我们研究p = 2的三项式模拟。

工作mod 2并遵循Nathan Fine的证明,

(1 + x + x^2)^{2^i} = 1 + x^{2^i} + x^{2^{2 i}}

(1 + x + x^2)^n
    = prod_i ((1 + x + x^2)^{2^i n_i})
        where n = sum_i n_i 2^i and n_i in {0, 1} for all i
        (i.e., n_i is the binary representation of n
    = prod_i (1 + x^{2^i n_i} + x^{2^i 2 n_i})
    = prod_i sum_{m_i = 0}^{2 n_i} x^{2^i}
    = sum_{(m_i)} prod_i x^{2^i m_i}
        taken over sequences (m_i) where 0 ≤ m_i ≤ 2 n_i.

在二项式情况下,下一步是观察到,对于系数x^m,最多只有(m_i)x^{2^i m_i}因子具有m因子的选项正确的产品,即(m_i)的二进制表示。

在三项式情况下,我们必须考虑m的二进制伪表示i,其中伪比特可以是零,一或两。当且仅当n_i = 0所有m_i = 0 n时,我们才有m

我们可以编写一个逐位扫描aa (0:0:nm') -> a nm' [emit 0] a (1:0:nm') -> a nm' [emit 0] -> b nm' [emit 2] a (1:1:nm') -> a nm' [emit 1] b (0:1:nm') -> a nm' [emit 0] b (1:0:nm') -> b nm' [emit 1] b (1:1:nm') -> a nm' [emit 0] -> b nm' [emit 2] 的自动机。状态def trinomial_mod_two(n, m): a, b = 1, 0 while m: n1, n = n & 1, n >> 1 m1, m = m & 1, m >> 1 if n1: if m1: a, b = a ^ b, b else: a, b = a, a ^ b elif m1: a, b = b, 0 else: a, b = a, 0 return a 是最初的并且正在接受。

def trinomial_mod_two_branchless(n, m):
    a, b = 1, 0
    while m:
        n1, n = n & 1, n >> 1
        m1, m = m & 1, m >> 1
        a, b = ((n1 | ~m1) & a) ^ (m1 & b), ((n1 & ~m1) & a) ^ (n1 & b)
    return a

我们可以使用动态编程来计算路径。以代码形式:

row1 = [(2,2), (4,4)]
row2 = [(5,5)]
row3 = [10, 20, 30, 40]
row_tuple_list = []
for r1 in row1:
    for r2 in row2:
        for r3 in row3:
            row_tuple_list.append((r1, r2, r3))

row_index = pd.MultiIndex.from_tuples(row_tuple_list, names=['row1', 'row2', 'row3'])

col1 = ['f', 'i']
col2 = ['g', 'h']
col_tuple_list = []
for c1 in col1:
    for c2 in col2:
        col_tuple_list.append((c1, c2))

col_index = pd.MultiIndex.from_tuples(col_tuple_list, names=['col1', 'col2'])

df = pd.DataFrame(index=row_index, columns=col_index)

giggles的无分支版本:

col1                  f         i     
col2                  g    h    g    h
row1   row2   row3                    
(2, 2) (5, 5) 10    NaN  NaN  NaN  NaN
              20    NaN  NaN  NaN  NaN
              30    NaN  NaN  NaN  NaN
              40    NaN  NaN  NaN  NaN
(4, 4) (5, 5) 10    NaN  NaN  NaN  NaN
              20    NaN  NaN  NaN  NaN
              30    NaN  NaN  NaN  NaN
              40    NaN  NaN  NaN  NaN

答案 2 :(得分:3)

感兴趣的系数取决于从x²+ x + 1 中选择 n 项的方式的数量,以便所选项的幂的总和为。这些方法可以分组,这些组具有相同数量的选定术语和 x 术语(选择 1 的次数来自那)。

a 术语的数量, b x 术语的数量,以及< em> c 特定组中 1 条款的数量。

然后是以下等式:

2a + b = m
a + b + c = n

显然,通常有几个组具有 a,b,c 的不同值。确定 a 后,还会确定 b c 的值。因此,只需迭代 a 的可能值即可获得所有组。

如果您要编写一个强力算法来获取系数本身,它在Python中将如下所示:

def combi(n, k): # number of ways to take k elements from n elements
    import math
    f = math.factorial
    return f(n) // f(k) // f(n-k)    

def get_coeff(n, m):
    if m > n * 2 or n < 0 or m < 0: # basic argument check
        return None
    if m > n: # mirrored situation is the same
        m = 2*n - m            
    coeff = 0
    for a in range(0, m//2+1):
        b = m - 2*a
        coeff += combi(n, a) * combi(n-a, b)
    return coeff

函数combi(n, k)将返回从n个元素中获取k个元素的方式的数量,即binomial coefficient

两次调用 combi 的产品回答了以下问题:

我可以用多少种方式 一词和 b x 一词?请注意,一旦完成其他2个选项,可以采用常数项的方式为1。

现在,由于我们只需要知道最终系数是奇数还是偶数,我们也只需要知道二项式系数是奇数还是偶数。 正如math.stackexchange.com所述,这可以通过简单的位操作来确定:

def combi_parity(n, k):
    return (k & (n-k)) == 0

def get_coeff_parity(n, m):
    if m > n * 2 or n < 0 or m < 0: # basic argument check
        return None
    if m > n:
        m = 2*n - m # mirrored situation is the same
    coeff_odd = 0
    for a in range(0, m//2+1):
        b = m - 2*a
        # A product is odd only when both factors are odd (so we perform an "and")
        # A sum changes parity whenever the added term is odd (so we perform a "xor")
        coeff_odd ^= combi_parity(n, a) and combi_parity(n-a, b) 
    return coeff_odd

repl.it上看到它。

答案 3 :(得分:2)

好的,我只想到了一个解决方案。这是:

  1. 将等式想象为n次,(a.x^2 + b.x^1 + c).(a.x^2 + b.x^1 + c)...n次。 a,b和c是我一般假设的常数。
  2. 现在,我们必须从每个术语中选择一个术语,以便所有这些术语的乘法结果导致x ^ m
  3. 我现在可以说,我们必须找到方程的解,t1.2 + t2 = m其中t1不是x^2t2 x }。这是因为t1t2会使该术语成为k.x^m形式(k是常数)。这是找到这个等式的整体丢番图解,即找到所有令人满意的{t1, t2}
  4. 现在,我们必须在这里应用一些排列来寻找系数。假设你有一个解决方案{1, 2}用于前一步骤,那么对于这个二元组,系数将是(1^1.nC1).(2^2.(n-1)C2),它将是系数成分之一。如果你对所有Diophantine解决方案的所有这些系数项求和,你就会得到系数。
  5. 实现上述算法需要一些时间,所以我已经发布了这些步骤。

    注意:我搜索了一下,Diophantine解决方案有各种算法。以下是与此相关的一篇文章:How to solve Linear Diophantine equations in programming?

    编辑:正如一个例子所示,

    1. 假设我们有等式(x^2 + x^1 + x^1)^3,我们必须找到系数x^3。因此,我们有m = 3
    2. 单独编写等式是为了直观地看到步骤。是的,

      (x^2 + x^1 + x^1).(x^2 + x^1 + x^1).(x^2 + x^1 + x^1)

    3. 现在,我们要从每个中选择{x^2, x^1, 1}中的任何一个。有几种方法可以选择它以使表单倍增,x^3

    4. 为了解决这个问题,我们可以编写等式2.a + b = 3,其中a是no x ^ 2被选中,b是没有x被选中的次数。该等式的解是{0, 3}{1, 1}。现在因为,我们还必须考虑我们选择它们的顺序,我们将在下一步中应用组合学。

    5. 系数为2^0.3C0.3^3.3C3 + 2^1.3C1.3^1.2C1。现在在这里, 在第一项中,2^0.3C0.3^3.3C33C0表示选择0 x^2出现3C3意味着出现3次x会产生x^3,但我们也会乘以2^0因为2是等式中x^2的系数,类似地,3^3因为3是x的系数。同样,您可以使用与{1, 1}

    6. 相对应的第二个词
    7. 这最多可以加63,你可以通过手动倍增来验证,你会得到63。

    8. 希望我很清楚。