首页 > 试题广场 >

牛牛学数列6

[编程题]牛牛学数列6
  • 热度指数:21007 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}定义数列 \{A_n\} 如下:

\displaystyle A_n=<br />\begin{cases}<br />0,& n\in\{1\};\\<br />1,& n\in\{2,3\};\\<br />\displaystyle A_n = A_{n-3} + 2A_{n-2} + A_{n-1},& n \geqq 4.<br />\end{cases}

\hspace{15pt}给定正整数 n,求 A_n 的值。

输入描述:
\hspace{15pt}在一行中输入一个整数 n,满足 1 \leqq n \leqq 20


输出描述:
\hspace{15pt}输出一个整数,表示 A_n 的值。
示例1

输入

4

输出

3

说明

A_4 = A_1 + 2A_2 + A_3 = 0 + 2\times1 + 1 = 3
#include <stdio.h>

int main() {
    int a[20]={0, 1, 1};
    int n=0, i=0, result=0;
    scanf("%d", &n);
    if(n!=1&&n!=2&&n!=3)
    {
        for(i=3;i<=n;i++)
        {
            a[i]=a[i-3]+2*a[i-2]+a[i-1];
        }
    }
    printf("%d", a[n-1]);
    return 0;
}
发表于 2025-07-03 22:50:44 回复(1)
#include<iostream>;
#include<iomanip>;
#include<cmath>;
using namespace std;
int main()
{
    int n;
    cin >> n;
    int an[21] = { 0,0,1,1 };
    for (int i = 4; i <= 20; i++)
    {
        an[i] = an[i - 3] + 2 * (an[i - 2]) + an[i - 1];
        if (n == i)
        {
            cout << an[i];
            return 0;
        }
    }
    cout << an[n];
    return 0;
}
发表于 2025-08-02 16:32:46 回复(0)
没用数组和递归,单纯算值
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    int a = 0, b = 1, c = 1;
    if(n == 1){
        cout << "0";
        return 0;
    }
    if( n == 2 || n == 3){
        cout << "1";
        return 0;
    }
    int sum = 0;
    for(int i = 4; i <= n; ++i){
        sum = a + 2*b + c;
        a = b;
        b = c;
        c = sum;
    }
    cout << sum << endl;
}
// 64 位输出请用 printf("%lld")

发表于 2025-12-11 13:03:51 回复(1)

递归写法-裸递归

裸递归写法是纯粹的递归写法,这种写法的时间复杂度呈指数级增长。
#include <stdio.h> 
int solution(int n)
{
    if (n < 4)
    {
         return n == 1 ? 0 : 1;
    }
   
    return solution(n - 3) + 2 * solution(n - 2) + solution(n - 1);
}
int main() {
   
    int n = 0;
    scanf("%d", &n);
    printf("%d", solution(n));
    return 0;
}

递归写法-含有备忘录

含有备忘录(散列表)的递归。
用定长数组 memo[] 实现缓存数组,键就是 n,查找/插入均为 O(1)。
#include <stdio.h>
#include <stdint.h>

#define MAX 20
#define INVALID -1

uint32_t memo[MAX + 1];

uint32_t solution(uint32_t n)
{
    if (n < 4)
    {
         return n == 1 ? 0 : 1;
    }

    if (memo[n] != INVALID)
    {
        return memo[n];         // 已经计算过,直接返回
    }

    memo[n] = solution(n - 3) + 2 * solution(n - 2) + solution(n - 1);

    return memo[n];
}
int main() {
    
    uint32_t n = 0;

    // 初始化备忘录
    for (int i = 0; i <= MAX; i++)
    {
        memo[i] = INVALID;
    }

    scanf("%u", &n);

    printf("%u", solution(n));

    return 0;
}

非递归写法-迭代

题目已说明这是数列题,那么可以用指针移动的思想进行迭代。
#include <stdio.h>
#include <stdint.h>

uint32_t solution(uint32_t n)
{
    if (n < 4)
    {
        return n == 1 ? 0 : 1;
    }

    int cur = 0;    // 当前计算出的 An 值
    int a1 = 0, a2 = 1, a3 = 1; // a1 到 a3 类比于指针,初始分别指向数列的前 3 项

    for (uint32_t i = 4; i <= n; i++)
    {
        // 计算出当前 An 的值,即 Ai 的值(当 n = i 时,An 的值)
        // 此时的 cur 表示着 a4 指针
        cur = a1 + 2 * a2 + a3;

        // 指针移动
        a1 = a2;
        a2 = a3;
        a3 = cur;
    }

    return cur;
}
int main() {
    
    uint32_t n = 0;

    scanf("%u", &n);

    printf("%u", solution(n));

    return 0;
}


发表于 2025-08-12 01:21:20 回复(0)
n = int(input())
a = []
a1 = 0
for i in range(n):
    if i == 0:
        a.append(0)
    elif i >0 and i <= 2:
        a.append(1)
    else:
        a.append(a[a1]+2*a[a1+1]+a[a1+2])
        a1+=1
print(a[-1])
发表于 2025-05-27 11:49:51 回复(0)
n=int(input())
a=0
b=c=1
if n==1:
    print(0)
elif n==2 or n==3:
    print(1)
else:
    for i in range(4,n+1):
        a,b,c=b,c,a+2*b+c
    print(c)
发表于 2026-01-15 15:28:36 回复(0)
常规用数组解法
#include <stdio.h>

int main() {
    int a[20],n,i;
    scanf("%d",&n);
    a[0]=0;
    a[1]=a[2]=1;
    for(i=3;i<20;i++){
        a[i]=a[i-3]+2*a[i-2]+a[i-1];
    }
    
    printf("%d",a[n-1]);
    return 0;
}


发表于 2025-11-16 22:51:44 回复(0)
n=int(input())
p=1<=n<=20
a=[0]*(n+1)
a[1],a[2],a[3]=0,1,1
if p:
    for i in range(4,n+1):a[i]=a[i-3]+2*a[i-2]+a[i-1]
print(a[n])

发表于 2025-11-03 15:01:55 回复(0)
用递归
#include <iostream>
using namespace std;
int A(int n);
int main() {
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int n;cin >> n;
    int a;
    a = A(n);
    cout << a;
    return 0;
}
int A(int n){
    int sum ;
    if(n == 1)sum = 0;
    else if(n == 2 || n == 3) sum = 1;
    else if(n >= 4)
        sum = A(n - 3) + A(n - 2) * 2 + A(n - 1);
    return sum;
}
发表于 2026-01-19 14:48:35 回复(0)
n=int(input())
a=0
b=1
c=1
if n==1:
print(0)
if (n==2)|(n==3):
print(1)
for i in range(4,n+1):
a,b,c=b,c,a+2*b+c
print(c)
发表于 2026-01-14 16:05:27 回复(0)
n = int(input())
list_A = [0, 1, 1]

for i in range(3, n):
    list_A.append(list_A[i-3] + list_A[i-2] + list_A[i-2] + list_A[i-1]) #中间直接套公式

print(list_A[-1]) #切最后一个
发表于 2026-01-14 12:55:09 回复(0)
三种方法(不推荐第三种,精度连题目范围内都无法满足)
/*
 * 方法名称:迭代法(循环递推)
 * 原理:基于数列的边界条件(f(1)=0、f(2)=1、f(3)=1)和递推公式(f(n)=f(n-1)+2f(n-2)+f(n-3)),
 *       通过循环手动维护前三项的结果值,逐步迭代推进,直接计算出第n项结果,无递归调用,仅依赖循环变量更新。
 * 时间复杂度:O(n),循环执行n-3次(n≥4),单次循环操作均为常数时间。
 * 空间复杂度:O(1),仅使用固定个数的整型变量,不额外占用与n相关的空间。
 * 适用场景:1. 所有存在明确递推关系的数列计算;2. n较大时(无栈溢出风险),追求极低空间开销;
 *          3. 初学者易理解、易实现、易调试的场景;4. 对代码运行效率要求较高且需避免递归栈开销的场景。
 */
#include <stdio.h>

int main() {
    int n;
    if (scanf("%d", &n) != 1 || 1 > n || n > 20) {
        return 1;
    }
    if (n > 3) {
        // 初始化递推所需的前三项值,对应f(n-3)、f(n-2)、f(n-1)(初始为f(1)、f(2)、f(3))
        int a = 0, b = 1, c = 1;
        // 循环递推,从第3项推进到第n-1项,最终c为第n项结果
        for (int i = 3; i < n; i += 1) {
            // 临时保存当前f(n-1)的值,用于后续更新b
            int r = c;
            // 核心递推公式:计算当前第i+1项的值(即下一个c)
            c = c + 2 * b + a;
            // 更新前三项:a承接原f(n-2),b承接原f(n-1)
            a = b;
            b = r;
        }
        printf("%d", c);
    }
    else if (n > 1) {
        // n=2、3,对应边界条件f(2)=1、f(3)=1
        printf("1");
    }
    else {
        // n=1,对应边界条件f(1)=0
        printf("0");
    }
    return 0;
}
/*
 * 方法名称:记忆化递归法(递归+缓存)
 * 原理:利用递归函数贴合数列的数学递推公式,同时通过全局数组作为缓存容器,保存已计算完成的子问题结果,
 *       当再次需要该子问题结果时,直接从缓存中获取,避免重复递归计算,兼顾递归的简洁性和高效性。
 * 时间复杂度:O(n),每个子问题(f(1)到f(n))仅计算一次,后续直接命中缓存返回,无重复运算。
 * 空间复杂度:O(n),主要开销为缓存数组(长度n+1)和递归调用栈(深度最大为n-3),均与n线性相关。
 * 适用场景:1. 存在大量重复子问题的递推数列计算;2. 追求代码简洁直观、与数学公式高度吻合的场景;
 *          3. n不宜过大(通常n≤1000,避免递归栈溢出);4. 后续需修改递推公式,希望降低代码修改成本的场景。
 */
#include <stdio.h>
#include <string.h>

// 全局数组:缓存容器,存储f(1)到f(20)的结果,下标与n直接对应
int A[21];

// 记忆化递归函数,计算并返回第n项的结果
int a(int n) {
    // 缓存命中判断:若A[n]>-1,说明已计算过,直接返回缓存结果
    if (A[n] > -1) {
        return A[n];
    }
    // 缓存未命中:按递推公式递归计算,并将结果存入缓存(更新缓存)
    A[n] = a(n - 1) + 2 * a(n - 2) + a(n - 3);
    return A[n];
}

int main() {
    int n;
    if (scanf("%d", &n) != 1 || 1 > n || n > 20) {
        return 1;
    }
    // 将缓存数组A全部初始化为-1(0xff对应int类型的-1),标记未计算的子问题
    memset(A, 0xff, 84);
    // 初始化边界条件(递归锚点),存入缓存,作为递归的终止条件
    A[1] = 0, A[2] = A[3] = 1;
    // 调用递归函数,输出第n项结果
    printf("%d", a(n));
    return 0;
}
/*
 * 方法名称:闭式公式法(通项公式+复数运算)
 * 原理:针对三阶线性齐次常系数递推数列,通过特征方程法推导得到数列的闭式通项公式,
 *       利用高精度浮点运算和复数运算实现通项公式的计算,直接一步到位得到第n项结果,无需循环或递归。
 * 时间复杂度:O(1),所有计算均为常数时间的数***算,与n的大小无关,计算效率最优。
 * 空间复杂度:O(1),仅使用固定个数的高精度浮点变量和复数变量,不占用与n相关的额外空间。
 * 适用场景:1. 存在明确闭式通项公式的线性齐次递推数列计算;2. 对计算效率要求极高,追求常数时间复杂度的场景;
 *          3. n在高精度浮点类型(long double)的精度范围内(避免浮点误差累积);4. 无需理解递推过程,仅需快速获取结果的场景。
 */
#include <stdio.h>
#include <math.h>
#include <complex.h>

int main() {
    int n;
    if (scanf("%d", &n) != 1 || 1 > n || n > 20) {
        return 1;
    }
    // 初始化特征方程求解得到的核心常量,长双精度浮点型减少计算误差
    long double a = cbrtl(19 + sqrtl(33)), b = cbrtl(19 - sqrtl(33));
    // 定义三次单位根(复数),用于处理特征方程的共轭复根
    long double complex w = sqrtl(3) / 2 * I - 0.5, m = w * w;
    // 转换n为长双精度型,保证复数幂运算的参数类型匹配
    long double complex N = n;
    // 计算特征方程的三个根(r1为实根,r2、r3为共轭复根)
    long double complex r1 = (1 + a + b) / 3, r2 = (1 + w * a + m * b) / 3, r3 = (1 + m * a + w * b) / 3;
    // 计算通项公式的权重系数,平衡三个幂次项的贡献
    long double complex c1 = 1 / ((r2 - r1) * (r3 - r1)), c2 = 1 / ((r1 - r2) * (r3 - r2)), c3 = 1 / ((r3 - r1) * (r3 - r2));
    // 核心:执行通项公式计算,提取实部、四舍五入修正误差、转换为整型输出
    printf("%d", (int)round(creal(c1 * cpowl(r1, N) + c2 * cpowl(r2, N) + c3 * cpowl(r3, N))));
    return 0;
}



发表于 2026-01-09 20:38:00 回复(0)
shuru = int(input())
list = [0, 1, 1]
a = 3
if shuru < 4:
    b = shuru - 1
    print(list[b])
while a < shuru:
    c = list[-3] + 2 * list[-2] + list[-1] 
    list.append(c)
    a += 1
print(list[-1])

发表于 2026-01-07 15:06:11 回复(0)
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < arr.length;i++){
            if(i == 0){
                arr[i] = 0;
            }else if(i == 1 || i == 2){
                arr[i] = 1;
            }else{
                arr[i] = arr[i-3]+2*arr[i-2]+arr[i-1];
            }
        }
        System.out.println(arr[n-1]);
    }
}
发表于 2026-01-06 15:52:24 回复(0)
        Scanner in = new Scanner(System.in);
        int a = in.nextInt();
        if (a == 1) {
            System.out.println(0);
            return;
        } else if (a == 2 || a == 3) {
            System.out.println(1);
            return;
        }
        int[] numArr = new int[a];
        numArr[0] = 0;
        numArr[1] = 1;
        numArr[2] = 1;
        for (int i = 3; i < a; i++) {
            numArr[i] = numArr[i - 3] + 2 * numArr[i - 2] + numArr[i - 1];
        }
        System.out.println(numArr[a - 1]);
发表于 2026-01-04 00:19:13 回复(0)
//递归思想很快,但费时间
#include <stdio.h>

int Fun(int num)
{
    if(num==1)
    {
        return 0;
    }
    else if(num>=2&&num<=3){
        return 1;
    }
    else 
        return Fun(num-3)+2*Fun(num-2)+Fun(num-1);
}

int main() {
    int num=0;
    scanf("%d",&num);
    int ret = Fun(num);
    printf("%d\n",ret);
    return 0;
}

发表于 2026-01-03 17:43:43 回复(0)
n =int(input())
 
while 1<=n<=20:
    if n >= 4:
        a = 0
        b,c = 1,1
        for i in range(4,n+1):
            d = a+2*b+c
            a = b
            b = c
            c = d
        print(int(d))
    elif n == 1:
        print(0)
    else:
        print(1)
    break
发表于 2026-01-01 15:46:52 回复(0)
#include <cassert>
#include <iostream>

int f(int n) {
    if (n == 1) {
        return 0;
    } else if (n == 2 || n == 3) {
        return 1;
    } else if (n >= 4) {
        return f(n - 3) + 2 * f(n - 2) + f(n - 1);
    } else {
        return -1;
    }
    return 0;
}

int main() {
    int n;
    std::cin >> n;
    assert(n >= 1 && n <= 20);

    std::cout << f(n) << "\n";

    return 0;
}

发表于 2025-12-31 10:34:55 回复(0)
先定义数组前三位,注意数组从0号位开始,
然后分段计算1-3直接输出值
大于3直接循环并赋值计算
#include <stdio.h>

int main() {
    int a, b[20]={0,1,1};
    int i=0;
    scanf("%d",&a);
    if(a<=3) {
        printf("%d",b[a-1]);
    }
    else{
       for(i=3;i<=a-1;i++){
        b[i]=b[i-1]+2*b[i-2]+b[i-3];
       }
       printf("%d",b[a-1]);
    }
    return 0;
}
发表于 2025-12-26 10:15:07 回复(0)
#include <stdio.h>

int main() {
    int n = 0;
    int a = 0,b = 1,c = 1;
    int d;
    scanf("%d",&n);
    if(n == 1)printf("0");
    if(n == 2 || n == 3)printf("1");
    if(n >= 4){
        for(int i = 4;i <= n;i++){
            d = a + 2*b + c;
            a = b;
            b = c;
            c = d;
        }
        printf("%d",c);
    }
    return 0;
}
发表于 2025-12-23 22:19:37 回复(0)