HDU 5447 Good Numbers (2015年长春赛区网络赛K题)
2015-09-17 19:47
676 查看
1.题目描述:点击打开链接
2.解题思路:本题利用唯一分解定理+gcd解决。这是我第一次用Java写题,忙了一下午终于通过了,真是太不容易了==。本题实际上就是把k1,k2分解后,把所有素因子的指数相乘就是答案。然而,k1,k2的范围太大了,高达10^24,为了方便使用大整数,直接上Java。
接下来就是考虑如何高效分解k1,k2了,注意到题目中给了一个条件:k1,k2的最大的素因子是相同的,第2大的素因子一定不同。这就提示我们可以考虑通过gcd来求解。假设gcd值是g。可以证明,如果把g中小于10^6的素因子全部分解掉,而且剩下部分仍然大于10^6的话,那么剩余部分一定是第1大素因子的1次幂,或2次幂,或3次幂。首先,g中一定包含第一大素因子,而且下一个包含的素因子至多是第3大素数,不妨设第一大素数为p1,第二大素数在k1中是p2,第三大素数是p3。那么如果g中含有p1的平方或立方,此时p3至多是10^6,然而10^6肯定是合数,因此p3一定早就被分解掉了。因此g中最后剩下的一定是p1^m。不难通过尝试求出p1。
求出p1后,把p1从k1,k2中除干净,并对k1,k2进行分解,那么不难证明,如果剩下的部分大于10^6,则一定是他们的第二大素数的2次幂或者是第二大素数和第3大素数,第4大素数等的乘积。证明方法同上。但是只有当第2大素数是2次幂时候才对答案有贡献,否则不用考虑它具体是多少,而且只要第2大素数是2次幂,那么第3大素数也一定小于10^6,在分解时候就能被找到。这样,算出大素数对应的幂次之后,小素数的幂次在分解时候就能顺便得到,累乘ans即可。
3.代码:
2.解题思路:本题利用唯一分解定理+gcd解决。这是我第一次用Java写题,忙了一下午终于通过了,真是太不容易了==。本题实际上就是把k1,k2分解后,把所有素因子的指数相乘就是答案。然而,k1,k2的范围太大了,高达10^24,为了方便使用大整数,直接上Java。
接下来就是考虑如何高效分解k1,k2了,注意到题目中给了一个条件:k1,k2的最大的素因子是相同的,第2大的素因子一定不同。这就提示我们可以考虑通过gcd来求解。假设gcd值是g。可以证明,如果把g中小于10^6的素因子全部分解掉,而且剩下部分仍然大于10^6的话,那么剩余部分一定是第1大素因子的1次幂,或2次幂,或3次幂。首先,g中一定包含第一大素因子,而且下一个包含的素因子至多是第3大素数,不妨设第一大素数为p1,第二大素数在k1中是p2,第三大素数是p3。那么如果g中含有p1的平方或立方,此时p3至多是10^6,然而10^6肯定是合数,因此p3一定早就被分解掉了。因此g中最后剩下的一定是p1^m。不难通过尝试求出p1。
求出p1后,把p1从k1,k2中除干净,并对k1,k2进行分解,那么不难证明,如果剩下的部分大于10^6,则一定是他们的第二大素数的2次幂或者是第二大素数和第3大素数,第4大素数等的乘积。证明方法同上。但是只有当第2大素数是2次幂时候才对答案有贡献,否则不用考虑它具体是多少,而且只要第2大素数是2次幂,那么第3大素数也一定小于10^6,在分解时候就能被找到。这样,算出大素数对应的幂次之后,小素数的幂次在分解时候就能顺便得到,累乘ans即可。
3.代码:
import java.math.BigInteger; import java.util.Arrays; import java.util.Scanner; public class Main{ final static int N=1000000+10; static int vis[]=new int ; static int primes[]=new int ; static int e1[]=new int ; static int e2[]=new int ; static int e3[]=new int ; static int v1[]=new int[100]; static int v2[]=new int[100]; static int v3[]=new int[100]; static int c1,c2,c3; static int idx; public static void main(String[] args) { BigInteger k1,k2; int T; sieve(); BigInteger bound=BigInteger.valueOf(1000000);//最大界限 Scanner in=new Scanner(System.in); T=in.nextInt(); while(T-->0) { init(); k1=in.nextBigInteger(); k2=in.nextBigInteger(); BigInteger g=k1.gcd(k2); k1=factor(v1,e1,k1);//v数组记录素因子的下标,e数组记录素因子的幂次 k2=factor(v2,e2,k2); g=factor(v3,e3,g); long r1=1,r2=1; if(g.compareTo(bound)==1) { if(is_ok(2,g)) g=getRoot(2,g);//找到第1大素数 else if(is_ok(3,g)) g=getRoot(3,g); } if(k1.compareTo(bound)==1) { int t1=0; while(k1.mod(g).equals(BigInteger.ZERO))//将第1大素数除干净 { k1=k1.divide(g); t1++; } r1*=t1; if(k1.compareTo(bound)==1&&is_ok(2,k1))//如果剩下部分仍然大于10^6且是某个素数的2次幂,那么该素数就是第二大素数,否则,后面所有大素数都不必考虑 r1*=2; } if(k2.compareTo(bound)==1) { int t2=0; while(k2.mod(g).equals(BigInteger.ZERO)) { k2=k2.divide(g); t2++; } r2*=t2; if(k2.compareTo(bound)==1&&is_ok(2,k2)) r2*=2; } for(int i=0;i<100;i++)//累乘分解后的幂次 { int id=v1[i]; if(id<0)break; r1*=e1[id]; } for(int i=0;i<100;i++) { int id=v2[i]; if(id<0)break; r2*=e2[id]; } System.out.println(r1+" "+r2); } } static void sieve() { Arrays.fill(vis, 0); idx=0; int m=(int)Math.sqrt(N); for(int i=2;i<=m;i++) if(vis[i]==0) for(int j=i*i;j<N;j+=i) vis[j]=1; for(int i=2;i<N;i++) if(vis[i]==0) primes[idx++]=i; } static void init() { Arrays.fill(e1, 0); Arrays.fill(e2, 0); Arrays.fill(e3, 0); Arrays.fill(v1, -1); Arrays.fill(v2, -1); Arrays.fill(v3, -1); } static boolean is_ok(int d,BigInteger a)//如果a是某个数的d次幂 { BigInteger t,mul; if(d==2) t=BigInteger.valueOf((long)Math.sqrt(a.doubleValue())); else t=BigInteger.valueOf((long)Math.pow(a.doubleValue(), 1.0/3)); mul=BigInteger.ONE; for(int i=0;i<d;i++)mul=mul.multiply(t); if(a.equals(mul))return true; t=t.add(BigInteger.ONE); mul=BigInteger.ONE; for(int i=0;i<d;i++)mul=mul.multiply(t); if(a.equals(mul))return true; return false; } static BigInteger getRoot(int d,BigInteger a)//求a的d次方根 { BigInteger t,mul; if(d==2)t=BigInteger.valueOf((long)Math.sqrt(a.doubleValue())); else t=BigInteger.valueOf((long)Math.pow(a.doubleValue(), 1.0/3)); mul=BigInteger.ONE; for(int i=0;i<d;i++) mul=mul.multiply(t); if(a.equals(mul))return t; else return t.add(BigInteger.ONE); } static BigInteger factor(int v[],int e[],BigInteger a) { int c=0; long m=(long)Math.sqrt(a.doubleValue()); for(int i=0;i<idx&&primes[i]<=m;i++) { BigInteger j=BigInteger.valueOf(primes[i]); if(a.mod(j)==BigInteger.ZERO) { e[i]=0; v[c++]=i; while(a.mod(j)==BigInteger.ZERO) { e[i]++; a=a.divide(j); } } } return a; } }
相关文章推荐
- Understanding ActiveMQ Broker Networks - 理解ActiveMQ 网络模型
- Linux内核工程导论——网络:服务质量与安全性
- 分享一个监控网络,磁盘使用,平均负载和RAM使用的shell脚本
- Android服务器与客户端数据交互(Http协议)
- 黑马程序员 java socket用tcp与udp实现
- 黑马程序员 JAVA的网络编程
- 离robots.txt启动网络爬虫之旅
- on duplicate key update简单使用
- Linux netstat命令详解和使用例子(显示各种网络相关信息)
- (转)如何创建Filter的属性页 [此博文包含图片] (2012-09-06 10:15:58) 转载 ▼ 标签: 杂谈 分类: DirectShow http://blog.csdn.net/
- 配置https实现请求安全
- 实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法
- http://www.cnblogs.com/king-77024128/articles/2666230.html
- iOS9 HTTP 不能正常使用的解决办法
- 推荐一款轻量级的linux系统和网络监控工具
- TCP通信
- Clover 资源管理器 http://cn.ejie.me/
- gem sources --add http://ruby.taobao.org/
- Loadrunner中对https证书的配置
- Xcode7中网络连接异常的问题