数的计算(洛谷)

题目

原题

题目描述

给出正整数 n n n,要求按如下方式构造数列:

  1. 只有一个数字 n n n 的数列是一个合法的数列。
  2. 在一个合法的数列的末尾加入一个正整数,但是这个正整数不能超过该数列最后一项的一半,可以得到一个新的合法数列。

请你求出,一共有多少个合法的数列。两个合法数列 a , b a, b a,b 不同当且仅当两数列长度不同或存在一个正整数 i ≤ ∣ a ∣ i \leq |a| ia,使得
a i ≠ b i a_i \neq b_i ai=bi

输入格式

输入只有一行一个整数,表示 n n n

输出格式

输出一行一个整数,表示合法的数列个数。

样例 #1

样例输入 #1

6

样例输出 #1

6

提示

样例 1 解释

满足条件的数列为:

  • 6 6 6
  • 6 , 1 6, 1 6,1
  • 6 , 2 6, 2 6,2
  • 6 , 3 6, 3 6,3
  • 6 , 2 , 1 6, 2, 1 6,2,1
  • 6 , 3 , 1 6, 3, 1 6,3,1

数据规模与约定

对于全部的测试点,保证 1 ≤ n ≤ 1 0 3 1 \leq n \leq 10^3 1n103

思路

根据题目所述

在一个合法的数列的末尾加入一个正整数,但是这个正整数不能超过该数列最后一项的一半

这样可以知道,每个数列实际有用的数就是最后一位。例如有以下数列

12 6 3

在这三个数中,唯一起作用的是数字3,前面的数是什么和组成数列的个数没有关系。递归思路是:

对于给定输入n

  • 先遍历第二元素可能的值。由题知该数是[1,n/2]中任意数,因此对该范围遍历。
  • 第一轮遍历假设第二位元素位置填n/2,则下一个位置中数的范围是[1,n/4],对该范围进行遍历
    …………
  • 当最后的数是1可以知道合法数列个数是1

合法数列个数就是以1~n/2的整数结尾时合法个数相加
这里还需要考虑的一种请况是对于给定尾数的数列,可以不向数列尾添加数。因此合法数列的个数还要加1,因此对于一个数列结尾是n的数列,合法数列个数是

f(n)=f(1)+f(2)+f(3)+…+f(n/2)+1
此处又有 f(n/2)=f(1)+f(2)+ff(3)+…+f(n/4)+1

f(2)=f(1)+1

代码

#include
using namespace std;
long long int d[1001];
int len;
long long int fun(int a){
	if(len>=a)
		return d[a];
	for(int i=1;i<=a/2;i++)
		d[a]+=fun(i);
	d[a]+=1;
	len++;
	return d[a];
}

int main(){
	d[1]=1;
	len=1;
	int n;
	cin>>n;
	cout<<fun(n);
}

后面看了下题解,题解里有位大佬用了更简单的方法和代码:
https://www.luogu.com.cn/blog/L-OnceL/solution-p1028

你可能感兴趣的:(算法,数据结构,笔记)