序列计数

本文探讨了一种特殊的正整数序列,其中序列的第一项为给定的n,第二项不超过n,从第三项开始,每一项都小于前两项之差的绝对值。文章提供了一个算法解决方案,用于计算满足这些条件的序列数量,并通过Java代码实现了这一算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

具体问题:

【问题描述】
小明想知道,满足以下条件的正整数序列的数量:
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。


代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

/**
 * @author 作者:ILove996
 * @version 创建时间:2020年3月25日 下午2:03:16 类说明
 */
public class Main {
	public static void main(String[] args) {
		ArrayList<ArrayList<Integer>> resList = new ArrayList<ArrayList<Integer>>();
		ArrayList<ArrayList<Integer>> tempList = new ArrayList<ArrayList<Integer>>();
		ArrayList<ArrayList<Integer>> acceptList = new ArrayList<ArrayList<Integer>>();

		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		in.close();
		
		for (int i = 1; i <= n; i++) {
			ArrayList<Integer> res = new ArrayList<Integer>();
			res.add(n);
			res.add(i);
			resList.add(res);
		}
		tempList.addAll(resList);

		while (tempList != null && tempList.size() > 0) {
			for (ArrayList<Integer> tl : tempList) {
				ArrayList<ArrayList<Integer>> nextItem = nextItem(tl);
				if (nextItem != null) {
					acceptList.addAll(nextItem);
				}
			}

			tempList.clear();

			if (acceptList != null && acceptList.size() > 0) {
				resList.addAll(acceptList);
				tempList.addAll(acceptList);
				acceptList.clear();
			}
		}

		ArrayList<String> strList = new ArrayList<String>();
		for (ArrayList<Integer> res : resList) {
			strList.add(toGoalString(res));
		}
		Collections.sort(strList);
		for (String string : strList) {
			System.out.println(string);
		}
	}

	private static ArrayList<ArrayList<Integer>> nextItem(ArrayList<Integer> res) {
		ArrayList<ArrayList<Integer>> resList = new ArrayList<ArrayList<Integer>>();
		int size = res.size();
		int abs = Math.abs(res.get(size - 1) - res.get(size - 2));

		if (abs <= 1) {
			return null;
		}

		for (int i = 1; i < abs; i++) {
			ArrayList<Integer> newRes = new ArrayList<Integer>();
			newRes.addAll(res);
			newRes.add(i);
			resList.add(newRes);
		}

		return resList;
	}

	private static String toGoalString(ArrayList<Integer> res) {
		StringBuffer sb = new StringBuffer();
		int size = res.size();
		for (int i = 0; i < size; i++) {
			sb.append(res.get(i));
			if (i < size - 1) {
				sb.append(" ");
			}
		}

		return sb.toString();
	}
}
运行结果:

在这里插入图片描述
在这里插入图片描述

### C++ 实现合法序列计数排序 为了实现合法序列计数排序,在C++中可以遵循特定的过程。此过程涉及创建辅助结构来追踪输入数组`A`中各个数值出现的频率,进而利用这些信息重新构建已排序的结果数组。 #### 创建并初始化计数数组 首先定义一个大小足以覆盖所有可能值域的计数数组`count[]`,其索引代表原始数组内的不同取值,而对应的元素保存着该位置所表示数字在原数组里的频次[^1]。 ```cpp #include <vector> using namespace std; void countingSort(vector<int>& nums, int maxVal) { vector<int> count(maxVal + 1, 0); // 初始化计数器 for (int num : nums) { // 统计各数值的数量 ++count[num]; } } ``` #### 计算累积和得到sum数组 接下来计算累计次数表即`sum[]`,这一步骤通过遍历`count[]`并将当前项与其之前所有的项目相加完成。这样做的目的是让每一个条目反映出不大于对应下标的总数量,从而指示最终排列后的具体放置地点[^2]。 ```cpp for (size_t i = 1; i <= maxVal; ++i) { count[i] += count[i - 1]; // 构建累加和数组 } ``` #### 排列目标数组 最后按照上述建立起来的信息填充输出数组`output[]`。这里需要注意的是,由于是从右向左处理输入列表中的每一项,因此能保持相同值得相对顺序不变——这是保证稳定性的重要措施之一。 ```cpp vector<int> output(nums.size()); // 倒序遍历nums以维持稳定性质 for (auto it = nums.rbegin(); it != nums.rend(); ++it) { output[count[*it] - 1] = *it; --count[*it]; } // 将结果复制回原数组 std::copy(output.begin(), output.end(), nums.begin()); ``` 整个函数封装如下: ```cpp void countingSort(vector<int>& nums, int maxVal) { if (nums.empty()) return; vector<int> count(maxVal + 1, 0); // Step 1: Count occurrences of each value. for (int num : nums) { ++count[num]; } // Step 2: Compute cumulative counts. for (size_t i = 1; i <= static_cast<size_t>(maxVal); ++i) { count[i] += count[i - 1]; } // Step 3: Place elements into their correct positions in the output array. vector<int> output(nums.size()); for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) { output[--count[*rit]] = *rit; } // Copy sorted data back to original vector. copy(output.begin(), output.end(), nums.begin()); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yelvens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值