4 条题解
-
0
针对“最长类斐波那契子序列”,我为你准备了这个集成化的数据生成器。它能够自动生成 10 组测试点,并根据竞赛逻辑实现了阶梯式难度,以确保暴力算法()能拿部分分,而只有 算法能拿满分。
数据生成器与标程 (C++14 标准)
该代码运行后会直接在当前目录下生成
1.in到10.out共 20 个文件。#include <iostream> #include <fstream> #include <vector> #include <string> #include <random> #include <unordered_map> #include <algorithm> #include <chrono> using namespace std; // ======================== 标程 (Solver) O(N^2) ======================== // 采用哈希表优化的 DP 算法,用于生成 .out 文件 int get_ans(int n, const vector<int>& a) { if (n < 3) return 0; unordered_map<int, int> val_to_idx; val_to_idx.reserve(n); for (int i = 0; i < n; ++i) val_to_idx[a[i]] = i; // dp[j][i] 表示以 a[j], a[i] 结尾的序列长度 // 使用一维数组模拟二维以提升内存连续性性能 vector<int> dp(n * n, 0); int max_len = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { int target = a[i] - a[j]; // 因为数组严格递增,target 必须小于 a[j] 才能保证其索引 k < j if (target < a[j] && val_to_idx.count(target)) { int k = val_to_idx[target]; dp[j * n + i] = dp[k * n + j] + 1; if (dp[j * n + i] == 1) dp[j * n + i] = 3; // 初始长度应为 3 (k, j, i) max_len = max(max_len, dp[j * n + i]); } } } return max_len >= 3 ? max_len : 0; } // ======================== 构造器 (Generator) ======================== void generate_test_case(int tid) { string in_name = to_string(tid) + ".in"; string out_name = to_string(tid) + ".out"; ofstream fin(in_name); mt19937 rng(tid + chrono::steady_clock::now().time_since_epoch().count()); int n; vector<int> a; const int INF = 1000000000; // --- 难度阶梯设计 --- if (tid <= 3) n = 150; // 暴力 O(N^3) 可过 else if (tid <= 6) n = 800; // O(N^2 log N) 勉强过,O(N^3) 必挂 else n = 2500; // 只有最优 $O(N^2)$ 可过 // --- 数据分布构造 --- if (tid == 2) { // 边界点:构造完全没有解的情况 (等比数列) for(int i=0; i<n; ++i) a.push_back(100 + i * 1000000); } else if (tid == 3) { // 构造:包含一个极长的斐波那契序列 vector<long long> fib = {1, 2}; while(fib.back() < INF) { fib.push_back(fib[fib.size()-1] + fib[fib.size()-2]); } for(auto v : fib) if(v <= INF) a.push_back((int)v); while((int)a.size() < n) a.push_back(rng() % INF); } else { // 普通构造:随机增加的序列 // 为了增加成链几率,随机选取两个数作为起点构造若干短链 for(int i=0; i < n/10; ++i) { long long v1 = rng() % 1000 + 1; long long v2 = v1 + rng() % 1000 + 1; a.push_back((int)v1); a.push_back((int)v2); while(v1 + v2 <= INF) { long long v3 = v1 + v2; a.push_back((int)v3); v1 = v2; v2 = v3; if(rng() % 10 == 0) break; // 随机断裂 } } while((int)a.size() < n) a.push_back(rng() % INF); } // 必须保证严格递增且不重复 sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); n = a.size(); // 写入文件 fin << n << "\n"; for (int i = 0; i < n; ++i) fin << a[i] << (i == n - 1 ? "" : " "); fin.close(); // 计算标准答案 ofstream fout(out_name); fout << get_ans(n, a) << endl; fout.close(); cout << "Test Case " << tid << " generated: N=" << n << endl; } int main() { cout << "Generating 10 test cases for Longest Fibonacci-Like Subsequence..." << endl; for (int i = 1; i <= 10; ++i) { generate_test_case(i); } cout << "Done." << endl; return 0; }数据分布与复杂度分析
测试点 范围 构造特征 区分算法 1 随机分布 基础 暴力能拿分 2 无合法子序列 测试对 max_len < 3返回 0 的处理3 包含标准 链 验证最长路径检索能力 4-6 混合随机链 超时, 刚好 AC 7-10 大规模稀疏/稠密链 必须使用 (哈希或双指针) 关键设计点说明
- 区分算法复杂度:
- 是关键。 的操作次数约为 ,在 C++ 中配合哈希表查找约耗时 。
- 的操作次数约为 ,在 1 秒时限内绝对无法通过。
- 文件大小控制:
- 即使是 的测试点,每个整数约 10 字节,文件大小约 。10 组总大小约 ,远低于 的限制。
- 安全性与异常:
- 严格递增:使用了
sort+unique,满足题目“严格递增”的要求。 - 溢出处理:在生成 Fibonacci 链时使用了
long long判断,防止计算 时超过int上限导致死循环。 - 非递归实现:标程和生成器均采用循环结构,避免深度递归导致的爆栈。
- 严格递增:使用了
- 随机性:
- 使用
mt19937配合时间戳种子,保证每次生成的数据分布均匀且不重复。
- 使用
使用方法:
- 将代码保存为
gen.cpp。 - 编译运行:
g++ gen.cpp -o gen -O3 -std=c++14。 - 执行
./gen,即可在文件夹内看到 20 个标准的测试文件。
- 区分算法复杂度:
信息
- ID
- 19492
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者