1 条题解
-
0
解题思路
这道题要求我们找出一个给定多项式的所有整数根。根据数学中的多项式理论,一个整系数多项式的整数根必须是常数项的因数。因此,我们可以通过以下步骤来解决这个问题:
- 预处理质数:生成所有小于60000的质数,用于后续分解常数项的质因数。
- 分解常数项:对于每个输入的多项式,分解其常数项的质因数,从而得到所有可能的因数。
- 验证可能的根:使用多个模数进行哈希验证,检查每个可能的因数是否为多项式的根。
- 多项式降阶:找到一个根后,使用综合除法将多项式降阶,继续寻找剩余的根。
题意分析
输入是一个多项式,其最高次项系数为1,其他系数为整数。我们需要找出该多项式的所有整数根,并按升序输出。特别注意,如果有重根,每个根都需要被列出。
标程
以下是完整的解题代码,包含详细注释:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define int64 __int64 // 使用64位整数类型 using namespace std; // 多个模数用于哈希验证,减少误判的可能性 int64 MOD[]={13251349,13251361,13251367, 13251373,13251377,13251383}; int64 prime[60000],isprime[60000],cnt; // 存储质数及其标记 // 预处理质数表(埃拉托斯特尼筛法) void init() { int64 i,j; cnt=0; for(i=2;i<60000;i++) { if(!isprime[i]) prime[++cnt]=i; // 如果i是质数,加入质数表 for(j=1;j<=cnt&&prime[j]*i<60000;j++) { isprime[prime[j]*i]=1; // 标记合数 if(i%prime[j]==0) break; // 优化筛法 } } } // 存储质因数及其指数的结构体 struct node { int64 prime,num; }; node a[100]; // 存储分解后的质因数 int64 n,aNum,factor[10000],factorNum; // 多项式次数、因数相关变量 int64 coef[105]; // 存储多项式系数 // 计算绝对值 int64 ABS(int64 x) { if(x<0) return -x; return x; } // 深度优先搜索生成所有可能的因数 void DFS(int64 x,int dep) { int64 i; if(dep==aNum+1) { factor[factorNum++]=x; // 生成一个因数 } else { for(i=0;i<=a[dep].num;i++) { DFS(x,dep+1); x=x*a[dep].prime; // 累乘当前质因数 } } } // 分解质因数并生成所有可能的因数 void cal(int64 p) { aNum=0; int64 i; // 分解质因数 for(i=1;i<=cnt;i++) if(p%prime[i]==0) { aNum++; a[aNum].prime=prime[i]; a[aNum].num=0; while(p%prime[i]==0) { a[aNum].num++; p/=prime[i]; } } if(p>1) // 处理剩余的质因数 { aNum++; a[aNum].prime=p; a[aNum].num=1; } factorNum=0; DFS(1,1); // 生成所有因数 } // 使用多个模数验证是否为根 int OK(int64 a) { int64 r,b,i,j; for(i=0;i<6;i++) { r=0; b=a%MOD[i]; // 霍纳法则计算多项式在模MOD[i]下的值 for(j=n;j>=0;j--) r=(r*b+coef[j])%MOD[i]; if(r) return 0; // 如果不为0,则不是根 } return 1; // 所有模数下都为0,大概率是根 } int64 ans[10005],ansNum; // 存储找到的根及其数量 int main() { init(); // 预处理质数表 while(scanf("%d",&n)!=-1) // 处理多个测试用例 { int64 i,j,k,t,r,u; // 读取多项式系数(注意输入顺序与存储顺序的转换) for(i=n-1;i>=0;i--) scanf("%I64d",&coef[i]); coef[n]=1; // 最高次项系数为1 ansNum=0; k=0; factorNum=0; // 迭代寻找所有根 while(n) { if(coef[0]==0) // 如果常数项为0,说明x=0是一个根 { ans[ansNum++]=0; // 多项式降阶(去掉x的因子) for(i=0;i<n;i++) coef[i]=coef[i+1]; n--; } else { if(!factorNum) cal(ABS(coef[0])); // 分解常数项的质因数 t=0; // 检查每个可能的因数及其相反数 for(i=k;i<factorNum;i++) if(coef[0]%factor[i]==0) { if(OK(factor[i])) { t=factor[i]; k=i; break; } if(OK(-factor[i])) { t=-factor[i]; k=i; break; } } if(!t) break; // 没有找到更多根,退出循环 ans[ansNum++]=t; // 综合除法:用(x-t)除多项式,得到降阶后的多项式 r=0; for(i=n;i>=0;i--) { u=r*t+coef[i]; coef[i]=r; r=u; } n--; } } sort(ans,ans+ansNum); // 按升序排序 printf("%I64d\n",ansNum); // 输出根的数量 for(i=0;i<ansNum;i++) printf("%I64d\n",ans[i]); // 输出每个根 } return 0; }
算法解释
-
预处理质数表:使用埃拉托斯特尼筛法生成所有小于60000的质数,用于后续分解常数项的质因数。
-
分解质因数:对于给定的常数项,分解其质因数并生成所有可能的因数(包括正负因数)。
-
根的验证:使用多个模数对每个可能的因数进行验证,确保在多个模数下多项式的值都为0,从而减少误判的可能性。
-
多项式降阶:找到一个根后,使用综合除法将多项式除以(x - root),得到降阶后的多项式,继续寻找剩余的根。
这种方法充分利用了数学中的多项式理论和哈希验证技术,高效地找到了所有整数根,同时保证了结果的正确性。
- 1
信息
- ID
- 2472
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者