序列计数

蓝桥杯快来了,给大家分享一道蓝桥杯的题目


题目

小明想知道,满足以下条件的正整数序列的数量

  1. 第一项为 n;
  2. 第二项不超过 n;
  3. 从第三项开始,每一项小于前两项的差的绝对值。
    请计算,对于给定的 n,有多少种满足条件的序列。
    【输入格式】
    输入一行包含一个整数 n。
    【输出格式】
    输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。

【样例输入】
4
【样例输出】
7
【样例说明】
以下是满足条件的序列:
4 1
4 1 1
4 1 2
4 2
4 2 1
4 3
4 4
【评测用例规模与约定】
对于 20% 的评测用例,1 <= n <= 5;
对于 50% 的评测用例,1 <= n <= 10;
对于 80% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 1000。

题解基本思路(看了大家的一些题解,总觉得有些复杂~~)

  • 首先从样例输出来看,该序列的长度至少为2

  • 用递归枚举的方法来做这道题肯定是很耗时的,所以采用一点动态规划的思想

  • First, 先考虑长度为2的序列, n1 n2;类似于 1 1,2 1, 2 2这样。

  • Second, 我们考虑长度为3的序列,从样例来看,类似于 4 1 1, 4 2 1,4 1 2 这样的序列;我们只需观察该序列中的2,3两位,你会发现有熟悉 1 1, 2 1,他们属于我们n=1,n=2中符合条件的序列,也就是First中的情况;但是,你也会发现这里误入了一个 1 2,它似乎就让我们有点陌生了。

  • Then,我们在考虑长度为4的序列... 哈哈哈,皮一下,其实我们考虑以上两种情况就足以了。

Summarize

  • 刚刚只是给大家引了下路,这里给大家举个例子,对于给定的数字n,我用f(a,b)表示序列以a,b开头的序列的个数,如f(1,1)=1, f(4,1)=3,这个可以简单的笔算出来。

  • 规律就是,如果我们想知道所有 以5 2 ...开头的序列的个数,我们是不是只需要知道以2 1, 2,2开头的序列的个数和就行了呢?(因为从第三项开始,每一项小于前两项的差的绝对值)而要知道 2 1, 2,2开头序列的个数,就可以从第一步轻松得到;即使上升一个较大的数值n,我们也能够递推至最小的子问题,只要我们将每种不同开头的个数储存起来,就能避免很多的重复运算,接着往下看.

  • 在用二维数组处理时,我们假设 1 2( 1 4)这样特殊的"开头"的序列存在,他们用来储存 n3<n2 时对应序列的值,这样就可以和上面统一了。对于如何得到这个值,如求1 4 这样开头的序列,我们只需在多处理一步,就又变成了4 1, 4 2这样我们熟悉的处理了。

python代码实现

def list_count(n):  
  '''
        动态规划: 构建 (n+1)*(n+1)整形矩阵
        buf[i][j]: (i>=1, j>=1) 表示 i,j..开头的序列
        4 1 2 3
        n1 n2 n3 n4
        由题:n1 > n2, n3<|n1 -n2|
        假设,如果将n1去掉后:n2,n3,n4 也满足要求
        此时存在情况:
        1:
            n2=n3, buf[n1][n2]=1
        2: 
            n2>n3, buf[n1][n2]=buf[n2][1]+...+buf[n2][ni] (1<i<n2-n3-1)
        3: 
            n2<n3,取|n2-n3|, buf[n1][n2]=buf[n3][1]+...+buf[n3][ni] (1<i<|n2-n3|)
    '''
  
  buf=[[0 for _ in range(0,n+1)] for _ in range(0,n+1)]
  for i in range(1,n+1):
      for j in range(1,i+1):
        #主处理
          if i-j>1:
              buf[i][j]+=1
              for k in range(1,i-j):
                  buf[i][j]+=buf[j][k]
          else:
              buf[i][j]+=1
          buf[i][j]%=10000
         #辅助处理,计算n3<n2时的值
      for x in range(1,i):
          buf[x][i]+=1
          for y in range(1, abs(x-i)):
              buf[x][i]+=buf[i][y]

  return sum(buf[n])%10000

如图:n=5时,buf的值为:

此方阵可以得到所有i<=n的结果,对buf[i]求和

posted on 2021-04-16 20:27  斤斤计较了  阅读(236)  评论(0编辑  收藏  举报