1 条题解
-
0
题目分析
我们需要计算满足特定条件的城市排列方案数。具体来说,每个城市的状态可以分为三种:">V"、"V"、"<"。通过动态规划(DP)来高效计算所有可能的排列数。
解题思路
-
状态定义:
- 设 表示第 个城市的状态为 ">V" 的方案数。
- 设 表示第 个城市的状态为 "V" 的方案数。
- 设 表示第 个城市的状态为 "<" 的方案数。
-
状态转移:
- ">V" 状态:只能由前一个城市的 ">V" 或 "V" 状态转移而来:
- "V" 状态:可以由前一个城市的任意状态转移而来:
- "<" 状态:同样可以由前一个城市的任意状态转移而来:
-
简化递推关系:
- 观察到 和 的转移方程相同,因此可以合并计算。
- 总方案数为三种状态之和:
- 代入转移方程后,可以推导出:
-
初始条件:
- 对于 (第一个城市):
- (">V")
- ("V")
- ("<")
- 总方案数 。
- 对于 (第二个城市):
- 根据转移方程计算 (假设 或根据实际情况调整)。
- 对于 (第一个城市):
关键优化
- 高精度处理:
- 由于 可能很大(如 ),直接计算会超出普通整数范围,需要使用高精度算术(如大数运算)。
- 递推优化:
- 利用矩阵快速幂或递推公式 加速计算。
复杂度分析
- 时间复杂度:
- 递推计算每个 的时间为 ,总时间为 。
- 若使用高精度运算,单次加法/乘法的复杂度为 ,总时间可能为 (取决于高精度实现)。
- 空间复杂度:
- 需要存储 数组,空间为 (或 如果仅保留最近两项)。
#include <iostream> #include <vector> using namespace std; vector<int> multiply_by_three(const vector<int>& num) { vector<int> result; int carry = 0; for (int d : num) { int product = d * 3 + carry; result.push_back(product % 10); carry = product / 10; } if (carry != 0) { result.push_back(carry); } return result; } vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> result; int borrow = 0; for (int i = 0; i < a.size(); ++i) { int a_digit = a[i]; a_digit -= borrow; int b_digit = (i < b.size()) ? b[i] : 0; if (a_digit < b_digit) { a_digit += 10; borrow = 1; } else { borrow = 0; } result.push_back(a_digit - b_digit); } while (result.size() > 1 && result.back() == 0) { result.pop_back(); } return result; } void print_number(const vector<int>& num) { for (auto it = num.rbegin(); it != num.rend(); ++it) { cout << *it; } cout << endl; } int main() { vector<vector<int>> a(101); a[1] = {1}; a[2] = {3}; for (int i = 3; i <= 100; ++i) { vector<int> term1 = multiply_by_three(a[i-1]); vector<int> term2 = a[i-2]; a[i] = subtract(term1, term2); } int n; while (cin >> n) { print_number(a[n]); } return 0; }
-
- 1
信息
- ID
- 206
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者