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

UVa 294 Divisors

题目分析本题要求给定若干个区间[L,U][L, U][L,U]在每个区间内找出一个数PPP使得PPP的正因数个数DDD最大。如果有多个数因数个数相同且均为最大则选取最小的那个数。最后按照指定格式输出结果。题目给出的数据范围是1⩽L⩽U⩽1081 \leqslant L \leqslant U \leqslant 10^81⩽L⩽U⩽108且区间长度满足0⩽U−L⩽100000 \leqslant U-L \leqslant 100000⩽U−L⩽10000。这意味着区间长度最大为10410^4104但单个数字本身最大可达10810^8108。一个最直接的想法是对于区间内的每个数通过试除法计算其因数个数然后比较得出最大值。但10810^8108级别的数字如果用n\sqrt{n}n​的试除法约为10410^4104次运算再乘以区间长度10410^4104总运算量约为10810^8108次对于NNN个区间来说可能超时。因此需要更高效的算法。解题思路因数个数定理根据数论知识若一个正整数nnn的质因数分解式为np1a1⋅p2a2⋯pkak n p_1^{a_1} \cdot p_2^{a_2} \cdots p_k^{a_k}np1a1​​⋅p2a2​​⋯pkak​​则nnn的正因数个数为d(n)(a11)(a21)⋯(ak1) d(n) (a_11)(a_21)\cdots(a_k1)d(n)(a1​1)(a2​1)⋯(ak​1)因此要求一个数的因数个数只需要得到它的质因数分解形式然后对每个指数加111后连乘即可。预处理素数表由于U⩽108U \leqslant 10^8U⩽108U≈10000\sqrt{U} \approx 10000U​≈10000。实际上316222≈10931622^2 \approx 10^9316222≈109因此只需要筛出316223162231622以内的所有素数即可对10810^8108以内的数进行质因数分解。代码中取上界为312633126331263稍大于316223162231622的近似值使用埃拉托色尼筛法Sieve\texttt{Sieve}Sieve得到所有素数存储在primes向量中。计算因数个数的两种方法代码中提供了两种计算因数个数的方法getCountOfDivisors1\texttt{getCountOfDivisors1}getCountOfDivisors1通过集合交替存储因数。每次处理一个质因数时将已有的因数集合中的每个数乘以该质因数得到新的因数然后交替存放在两个集合中。这种方法直接生成了所有因数适用于需要实际因数的场景但空间和时间开销较大。getCountOfDivisors2\texttt{getCountOfDivisors2}getCountOfDivisors2利用因数个数定理先进行质因数分解用map记录每个质因数的指数最后计算(指数11)×(指数21)×⋯(指数_11) \times (指数_21) \times \cdots(指数1​1)×(指数2​1)×⋯。这种方法只关心因数个数而不关心具体是哪些因数效率更高。代码最终使用的是第二种方法调用getCountOfDivisors2\texttt{getCountOfDivisors2}getCountOfDivisors2因为本题只需要因数个数进行比较无需枚举因数。特殊情况处理当n1n1n1时因数只有111本身返回111。当nnn是素数时因数只有111和nnn返回222。利用预处理好的素数表isPrime可以快速判断。在质因数分解后若n1n1n1剩余说明剩余部分是一个大于312633126331263的素数此时因数个数需要再乘222。主逻辑对于每个区间[L,U][L, U][L,U]遍历区间内的每一个数iii调用getCountOfDivisors2(i)\texttt{getCountOfDivisors2}(i)getCountOfDivisors2(i)计算其因数个数并与当前最大值比较。若遇到更大的因数个数则更新最大值和对应的最小数字PPP。由于区间长度最大仅为10410^4104即使每个数的计算需要分解质因数最多尝试108≈104\sqrt{10^8} \approx 10^4108​≈104以内的素数总计算量也是可接受的。复杂度分析预处理筛法求素数的时间复杂度约为O(nlog⁡log⁡n)O(n \log \log n)O(nloglogn)其中n≈31622n \approx 31622n≈31622非常快。单次因数个数计算最坏情况下需要遍历所有340134013401个素数316223162231622以内的素数个数约为340134013401每次除法运算很快。对于10810^8108附近的数质因数分解很快结束。整体对于每个区间最多计算100011000110001次因数个数每次最多约340134013401次除法总操作次数在3×1073 \times 10^73×107级别实际运行非常迅速。代码实现// Divisors// UVa ID: 294// Verdict: Accepted// Submission Date: 2016-05-09// UVa Run Time: 0.010s//// 版权所有C2016邱秋。metaphysis # yeah dot net#includebits/stdc.husingnamespacestd;vectorintprimes;// 存储筛法得到的素数intisPrime[31263];// 标记是否为素数的数组intN,L,U;// 埃拉托色尼筛法筛选出 31263 以内的所有素数voidsieve(){memset(isPrime,1,sizeof(isPrime));// 初始化所有数为素数for(inti2;i31263;i)if(isPrime[i]){// 将 i 的倍数标记为非素数for(intj2*i;j31263;ji)isPrime[j]0;primes.push_back(i);// 将素数存入向量}}// 方法一通过生成所有因数来计算因数个数本题实际未使用intgetCountOfDivisors1(intn){if(n1)return1;// 1 的因数只有自身if(n31263isPrime[n])return2;// 素数有 2 个因数setintnumbers,divisors;numbers.insert(1);// 初始因数集合包含 1for(inti0;iprimes.size();i){while(n%primes[i]0){n/primes[i];if(numbers.size()){// 将现有因数乘以当前质因子生成新因数for(autoitnumbers.begin();it!numbers.end();it){divisors.insert(*it);divisors.insert(*it*primes[i]);}numbers.clear();}else{for(autoitdivisors.begin();it!divisors.end();it){numbers.insert(*it);numbers.insert(*it*primes[i]);}divisors.clear();}}if(n1)break;// 分解完成}// 如果剩余 n 1说明还有一个大于 31263 的素因子if(n1)return2;// 返回两个集合中较大的那个即所有因数的数量returnmax(numbers.size(),divisors.size());}// 方法二利用质因数分解和因数个数定理效率更高实际使用的方法intgetCountOfDivisors2(intn){if(n1)return1;// 1 的因数只有自身if(n31263isPrime[n])return2;// 素数有 2 个因数mapint,intdivisors;// 记录质因子及其指数// 用预处理好的素数进行质因数分解for(inti0;iprimes.size();i){while(n%primes[i]0){n/primes[i];divisors[primes[i]];// 指数加 1}if(n1)break;}// 如果 n 1说明剩余部分是一个大于 31263 的素数if(n1)return2;// 根据因数个数定理(a11)*(a21)*...intcount1;for(autopair:divisors)count*(pair.second1);returncount;}// 在给定区间 [L, U] 内查找因数个数最多的数voidfindNumber(){intminNL,maxCountOfDivisors0,countOfDivisors;// 遍历区间内的每一个数for(intiL;iU;i)if((countOfDivisorsgetCountOfDivisors2(i))maxCountOfDivisors){maxCountOfDivisorscountOfDivisors;minNi;// 更新为当前因数个数更多的数由于遍历是从小到大相同个数时自然保留较小的}// 按要求格式输出结果coutBetween L and ;coutU, minN has a maximum of ;coutmaxCountOfDivisors divisors.\n;}intmain(intargc,char*argv[]){// 加速输入输出cin.tie(0),cout.tie(0),cin.sync_with_stdio(false);sieve();// 预处理素数表cinN;// 读入区间个数while(N--){cinLU;findNumber();}return0;}
http://www.zskr.cn/news/1400358.html

相关文章:

  • Hitboxer SOCD Cleaner:解决游戏键盘输入冲突的终极方案
  • 不确定系统中的多目标规划模型与应用【附代码】
  • 2026年5月液压升降平台厂家推荐:TOP5排名专业评测工业厂房重载升降性价比高 - 品牌推荐
  • Unity 2018+ 版本里,那个消失的Standard Assets去哪了?手把手教你从Asset Store找回并修复BUG
  • 微信聊天记录解密终极指南:3步快速恢复加密数据
  • ThinkPad开机滴滴响或显示Fan error/2100硬盘错误?保姆级拆机清灰与硬件检测指南(避免误判主板问题)
  • livox mid 360s使用记录
  • 面试复盘7.0
  • 个人笔记-wsl2 Ubuntu24.04安装oh-my-posh
  • 2026市面上耐用的给水pph管厂家推荐榜单 - 品牌排行榜
  • 面向AI智能体的API设计:从人类可读到机器可理解的技术演进
  • 终极炉石传说游戏增强插件:HsMod 55项功能完整指南
  • 2026年5月杨浦新房推荐:五大楼盘专业评测滨江置业防踩坑 - 品牌推荐
  • ExaLith PCIe卡:高性能AI推理的经济解决方案
  • 移动开发十年变革:从原生到跨平台,开发者如何重构技术栈应对挑战
  • C++字符串类实现详解
  • Windows最高权限获取终极指南:RunAsTI完整使用教程
  • ARM嵌入式开发中的堆栈内存管理与Keil配置实践
  • 深度解析EhViewer:如何用开源漫画应用打造个性化数字阅读空间
  • 基于Agora与AssemblyAI构建高精度实时语音转录机器人
  • EhViewer开源漫画阅读器:打造你的专属Android漫画图书馆
  • RTX内核栈溢出检测机制与配置指南
  • AI Agent架构解析:从大语言模型到自主执行体的工程实践
  • AI Artifact:从文本响应到可交互成品的生产力跃迁
  • 复杂环境干扰下频域模态参数识别与应用【附代码】
  • 从几何视角理解注意力机制:乘性门控如何塑造统计流形曲率
  • 从工具堆砌到流程重塑:构建端到端AI研究助理Archimedes
  • 深入解析Android占坑Activity原理:启动机制与实例化管理
  • 深入剖析Android Handler机制:原理、源码、实践与面试精要
  • 性价比高的沿海地区用耐生锈门扣推荐,好用不贵别错过 - mypinpai