当前位置: 首页 > news >正文

UVa 463 Polynomial Factorization

题目概述

给定一个4次整数系数多项式,要求将其分解为若干个质多项式(不可再分解的整数系数多项式)的乘积,并按照特定格式输出。

输入格式:多组测试数据,每组包含5个整数,表示4次多项式的系数(从4次项到常数项)

输出格式:每行输出一个质多项式的系数,按特定规则排序

算法思路

核心思想

本解法采用深度优先搜索(DFS)结合有理根定理的方法,系统地寻找多项式的整数系数因子。

关键步骤

1. 有理根定理的应用

对于整数系数多项式,任何有理根必为常数项因子与首项系数因子的比值。我们利用这一性质生成所有可能的线性因子候选。

2. 多项式除法

实现多项式长除法算法,检查候选因子是否能整除原多项式。

3. 递归分解
  • 优先尝试线性因子分解
  • 对于4次多项式,还尝试二次因子分解
  • 无法分解时,当前多项式即为质多项式
4. 系数归一化

确保输出满足题目要求:首项系数为正,系数互质

代码详解

多项式除法函数

bool divisible(vector<int> a, vector<int> b, vector<int>& q) {q.clear();for (int i = 0; i + b.size() <= a.size(); i++) {if (a[i] % b[0]) return false;      // 检查可除性int r = a[i] / b[0]; q.push_back(r); // 计算商的一项// 执行减法步骤for (int j = 0; j < b.size(); j++) a[i + j] -= r * b[j];}// 检查余数是否为零for (int x : a) if (x) return false;return true;
}

因子生成函数

void getFactors(int n, vector<int>& f) {f.clear();for (int i = 1; i * i <= n; i++) {if (n % i == 0) { f.push_back(i); f.push_back(n / i); }}
}

核心分解函数

bool dfs(int d, vector<int> in, vector<vector<int>>& out) {if (d == 1) { out.push_back(in); return true; } // 基本情况vector<int> p, q, r;getFactors(in[0], p);                    // 首项系数因子getFactors(abs(in.back()), q);           // 常数项因子// 生成所有可能的线性因子候选int qsize = q.size();for (int i = 0; i < qsize; i++) q.push_back(-q[i]);if (in.back() == 0) q.push_back(0);// 尝试线性因子分解for (int a1 : p) for (int c1 : q) {vector<int> t = {a1, c1};if (divisible(in, t, r)) {out.push_back(t);return dfs(d - 1, r, out);       // 递归分解商式}}// 二次因子分解(仅对4次多项式)if (d == 4) {// 尝试分解为两个二次多项式的乘积// 详细实现见完整代码}out.push_back(in); return false;
}

算法复杂度分析

  • 时间复杂度:最坏情况下需要检查所有可能的因子组合,但由于多项式次数固定为4,实际运行效率很高
  • 空间复杂度:主要消耗在递归调用栈和存储分解结果,由于深度有限,空间需求不大

样例分析

样例1

输入2 7 -1 -6 -2

分解过程

  1. 找到线性因子 (x - 1),执行除法得到 2x³ + 9x² + 8x + 2
  2. 找到线性因子 (2x + 1),执行除法得到 x² + 4x + 2
  3. x² + 4x + 2 无法再分解

输出

1 -1
2 1
1 4 2

样例2

输入2 0 0 0 0

分解2x⁴ = 2 × x × x × x × x

输出

1 0
1 0
1 0
2 0

实现要点

  1. 首项系数处理:如果输入首项系数为负,先整体取反,最后再调整回来

  2. 系数归一化:每个因子的系数要除以它们的最大公约数

  3. 输出排序

    • 按多项式次数升序排列
    • 同次数按字典序排列
    • 整体符号调整到最后一个多项式
  4. 边界情况:正确处理常数项为零的情况

总结

本题的关键在于合理应用有理根定理和系统性的搜索策略。通过优先尝试简单因子(线性因子),再考虑复杂分解(二次因子),算法能够在可接受的时间内找到正确的分解方案。系数归一化和输出排序的处理确保了结果符合题目要求。

参考代码

// Polynomial Factorization
// UVa ID: 463
// Verdict: Accepted
// Submission Date: 2025-10-07
// UVa Run Time: 0.080s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>
using namespace std;/*** 多项式除法:判断多项式a是否能被多项式b整除* @param a 被除多项式(系数向量,高次在前)* @param b 除多项式(系数向量,高次在前)* @param q 商多项式(输出参数)* @return 如果可整除返回true,否则返回false*/
bool divisible(vector<int> a, vector<int> b, vector<int>& q) {q.clear();// 模拟多项式长除法过程for (int i = 0; i + b.size() <= a.size(); i++) {// 检查当前最高次项是否能整除if (a[i] % b[0]) return false;// 计算商的一项int r = a[i] / b[0]; q.push_back(r);// 从被除数中减去商乘以除数的结果for (int j = 0; j < b.size(); j++) a[i + j] -= r * b[j];}// 检查余数是否为零(完全整除)for (int x : a) if (x) return false;return true;
}/*** 获取一个整数的所有因子(正因子)* @param n 输入整数* @param f 因子列表(输出参数)*/
void getFactors(int n, vector<int>& f) {f.clear();// 遍历1到sqrt(n)寻找因子for (int i = 1; i * i <= n; i++) {if (n % i == 0) { f.push_back(i);          // 小因子f.push_back(n / i);      // 对应的配对因子}}
}// 比较函数:按绝对值升序排序
bool cmpValue(int a, int b) { return abs(a) < abs(b); }// 比较函数:多项式排序(先按次数升序,次数相同按字典序)
bool cmpPoly(vector<int> a, vector<int> b) { return a.size() != b.size() ? a.size() < b.size() : a < b; 
}/*** 深度优先搜索分解多项式* @param d 当前多项式的次数* @param in 当前要分解的多项式系数* @param out 分解结果(输出参数)* @return 是否成功分解*/
bool dfs(int d, vector<int> in, vector<vector<int>>& out) {// 基本情况:次数为1,无法再分解if (d == 1) { out.push_back(in); return true; }vector<int> p, q, r;// 获取首项系数和常数项的所有因子getFactors(in[0], p);                    // 首项系数的因子getFactors(abs(in.back()), q);           // 常数项的因子(取绝对值)// 为常数项因子添加负值版本(因为根可能是负数)int qsize = q.size();for (int i = 0; i < qsize; i++) q.push_back(-q[i]);if (in.back() == 0) q.push_back(0);      // 处理常数项为零的情况// 按绝对值排序,优先尝试绝对值小的因子(提高效率)sort(p.begin(), p.end(), cmpValue); sort(q.begin(), q.end(), cmpValue);// 尝试所有可能的线性因子 (a1*x + c1)for (int a1 : p) for (int c1 : q) {vector<int> t = {a1, c1};            // 构造线性因子if (divisible(in, t, r)) {           // 检查是否能整除out.push_back(t);                // 将因子加入结果return dfs(d - 1, r, out);       // 递归分解商式}}// 如果次数较低(2或3)且找不到线性因子,直接返回原多项式if (d <= 3) { out.push_back(in); return true; }// 对于4次多项式,尝试二次因子分解 (a1*x² + b1*x + c1)(a2*x² + b2*x + c2)for (int a1 : p) for (int c1 : q) {int a2 = in[0] / a1, c2 = in.back() / c1;  // 计算配对系数// 根据多项式乘法展开,建立方程组:// 原多项式: a0*x⁴ + a1*x³ + a2*x² + a3*x + a4// 分解形式: (a1*x² + b1*x + c1)(a2*x² + b2*x + c2)// 展开后系数对应关系:// x⁴: a1*a2 = a0// x³: a1*b2 + a2*b1 = a1// x²: a1*c2 + b1*b2 + a2*c1 = a2  // x¹: b1*c2 + b2*c1 = a3// x⁰: c1*c2 = a4// 从x³和x¹的方程中解出b1和b2// 设方程为:a2*b1 + a1*b2 = a1  (x³系数)//          c2*b1 + c1*b2 = a3  (x¹系数)// 这可以看作关于b1, b2的线性方程组int aa = -a2, bb = in[1];            // 系数矩阵参数int cc = -(a1 * in[2] - a1 * a1 * c2 - a2 * c1 * a1);  // 计算判别式参数// 计算判别式int delta = bb * bb - 4 * aa * cc;if (delta < 0) continue;             // 无实数解int hh = sqrt(delta + 0.5);          // 开方(加0.5用于四舍五入)if (hh * hh != delta) continue;      // 检查是否为完全平方数// 尝试两个可能的根(正负两个解)for (int sign = -1; sign <= 1; sign += 2) {// 检查解是否为整数if ((sign * hh - bb) % (2 * aa)) continue;int b1 = (sign * hh - bb) / (2 * aa);  // 计算b1// 从x³方程计算b2,检查是否为整数if ((in[1] - b1 * a2) % a1) continue;int b2 = (in[1] - b1 * a2) / a1;// 验证x¹系数方程if (b1 * c2 + b2 * c1 != in[3]) continue;// 找到有效的二次因子分解out.push_back({a1, b1, c1}); out.push_back({a2, b2, c2});return true;}}// 无法分解,返回原多项式out.push_back(in); return false;
}int main() {cin.tie(0); ios::sync_with_stdio(false);  // 加速IOint a, b, c, d, e;while (cin >> a >> b >> c >> d >> e) {// 读取5个系数(4次多项式)vector<int> in = {a, b, c, d, e};// 如果首项系数为负,整体取反(保证首项系数为正)bool reversed = in[0] < 0;if (reversed) for (int& x : in) x *= -1;// 分解多项式vector<vector<int>> out;dfs(4, in, out);// 计算所有因子的最大公约数,用于归一化系数int g = 1;for (auto& poly : out) {int tmpg = 0;// 计算当前多项式的系数的GCDfor (int x : poly) if (x) tmpg = tmpg ? __gcd(tmpg, abs(x)) : abs(x);if (!tmpg) tmpg = 1;  // 处理全零情况g *= tmpg;// 将当前多项式系数除以GCD进行归一化for (int& x : poly) x /= tmpg;}// 如果之前取反过,现在将整体符号调整回来if (reversed) g = -g;// 对因子排序:先按次数升序,次数相同按字典序sort(out.begin(), out.end(), cmpPoly);// 将整体符号乘到最后一个因子上for (int& x : out.back()) x *= g;// 输出结果for (auto& poly : out) {for (auto it = poly.begin(); it != poly.end(); ++it) {cout << *it; if (next(it) != poly.end()) cout << " ";  // 空格分隔,最后无空格}cout << "\n";}cout << "\n";  // 每个测试用例后输出空行}return 0;
}
http://www.dtcms.com/a/453176.html

相关文章:

  • 老题新解|十进制转二进制
  • 数字信号处理 第八章(多采样率数字信号处理)
  • 网站制作农业免费封面设计在线制作生成
  • 多线程:三大集合类
  • html css js网页制作成品——化妆品html+css+js (7页)附源码
  • OpenAI战略转型深度解析:从模型提供商到全栈生态构建者的野望
  • 怎么做网站自动采集数据hao123设为主页官网下载
  • 重庆孝爱之家网站建设网站单页设计
  • 13、Linux 基本权限
  • k8s-ingress控制器
  • 【AI】深入 LangChain 生态:核心包架构解析
  • CodeBuddy Code + 腾讯混元打造“AI识菜通“
  • 记录踩过的坑-金蝶云·苍穹平台-杂七杂八
  • 【嵌入式原理系列-第11篇】半导体电子传输与PN结工作原理浅析
  • 磁力链接 网站怎么做的做网站多少钱西宁君博专注
  • 苹果RL4HS框架的技术原理
  • 在哪网站开发软件发视频的网址网址是什么?
  • 第74篇:AI+教育:个性化学习、智能辅导与虚拟教师
  • 2025 AI 落地元年:从技术突破到行业重构的实践图景
  • 《每日AI-人工智能-编程日报》--2025年10月7日
  • 公司销售泄密公司资料如何管控?信企卫文件加密软件深度分析
  • .NET+AI: (微家的AI开发框架)什么是内核记忆(Kernel Memory)?
  • 版本控制器 git(2)--- git 基本操作
  • 数字信号处理 第六章(IIR数字滤波器设计)
  • 辽宁专业网页设计免费建站正规seo服务商
  • 西安将军山网站建设wordpress评论模板怎么改
  • 抽象类定义
  • 基于sprigboot的农贸市场摊位管理系统(源码+论文+部署+安装)
  • 基于Flink的AB测试系统实现:从理论到生产实践
  • 开源 C++ QT QML 开发(八)自定义控件--圆环