南阳OJ 题目56-阶乘因式分解(一)

1.题目描述:题目链接

阶乘因式分解(一)

时间限制:3000 ms  |  内存限制:65535 KB
难度:2
描述

给定两个数m,n,其中m是一个素数。

将n(0<=n<=10000)的阶乘分解质因数,求其中有多少个m。

输入
第一行是一个整数s(0<s<=100),表示测试数据的组数随后的s行, 每行有两个整数n,m。
输出
输出m的个数。
样例输入
2
100 5
16 2
样例输出
24
15

2.解题思路

2.1 方法一:动态规划法

    输入n和m,要求n!中m的个数,n!=n*(n-1)*......*3*2*1.因此将公式展开,从1-n求解m的个数,存在求解的子问题,因此采用动态规划法。

2.2 方法二:超简单

    我这个傻货只想着高级的范式能有效的提高运行效率,却没有直接看出这个问题的求解,超简单。
  题目要求的是n!中m的个数,既在展开式中,能对m整除才能满足条件,有很多数字直接就不能满足了。因此,整个阶乘的展开式中就那么几个满足条件的特殊数字,记为a,b,c...好了,并且他们之间是有关系的:a=n,b=a/m,c=b/m,直到我们的特殊为0为止,而结果正巧是特殊数字的和(除a外)。
  举个例子:
  a=n=100,m=5; b=a/m=20; c=b/m=4;d=c/m=0;
  结果result=b+c+d=24
  

3.运行代码:

自己的编程习惯和算法
package 语言入门;

import java.util.Scanner;

/* Dragon 2017.7.24
 *  阶乘因式分解(一)
 *  方法一:用动态规划法来求解
 *  运行时间199ms
 */
public class Num_56 
{

	public static void main(String[] args) 
	{
		Scanner in=new Scanner(System.in);
		
		//输入数据组
		int number=in.nextInt();
		for(int i=0;i<number;i++)
		{
			//输入n和m
			int n=in.nextInt();
			int m=in.nextInt();
			
			//求解m的个数并输出
			int result=ZhiNumber(n,m);
			System.out.println(result);
		}

	}

	//使用动态规划的方法,求解中m的个数
	private static int ZhiNumber(int n, int m) 
	{
		//定义长度为n的数组,用于填表,保存的数字代表m的个数,下标从1开始
		int[] flag=new int[n+1];
		
		//让初始化的值为-1,若为0会有冲突
		for(int i=1;i<=n;i++)
			flag[i]=-1;
	
		/* 
		 * 接下来就是对flag数组进行填数和统一求和
		 * 例:flag[3]表示 n!中的因数3中m的个数
		 *  n!=1*2*3....*n  将因数都分开来填 
	     */
		
		//从1-n 开始填数
		int i=1; int j=1;
		while(i<=n)
		{
			j=i;
			int jCount=0;//当前数字内部的计数
			
			/* 单个数字的内部动态规划填数过程:
			 * 数j刚进来,可以判断是否可以整除,不满足条件,flag[j]=0,此时JCount=0
			 * 数j被整除进来的,也如此判断,不满足条件,flag[j]=JCount,JCount已内部变化
			 * j满足条件,JCount变化,j整除
			 */
			while( j%m==0 )
			{
				//去除重复项,有值
				if(flag[j] !=-1)
				{
					jCount=jCount+flag[j];
					break;
				}
				
				//之前未计算过的
				else
				{
					j=j/m;
					jCount++;
				}
			}
			
			flag[i]=jCount;
			
			//当前的数字求出结果,进行下一个
			i++;
		}
		
		//统一求flag中的和值过程
		int count=0;
		for(int p=1;p<=n;p++)
			count=count+flag[p];
		
		return count;
	}

}
我是分割线~
参考大神后的算法提高,即法二
package 语言入门;

import java.util.Scanner;
/*
 *  保留Scanner输入输出,修改算法
 *  运行时间61ms
 */

public class my {

	public static void main(String[] args) 
	{
		Scanner in=new Scanner(System.in);
		
		//输入数据组
		int number=in.nextInt();
		for(int i=0;i<number;i++)
		{
			//输入n和m
			int n=in.nextInt();
			int m=in.nextInt();
			int sum=0;
			
			//求解m的个数并输出
			while(n != 0){  
				n /= m;
				sum += n;
			}
			System.out.println(sum);
		}

	}

}




我是分割线~


package 语言入门;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/*
 * 大神4ms的代码
 */
public class 大神 {

	public static void main(String[] args) throws IOException{

		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		int count = getInt(stdin.readLine());
		int m,n,sum = 0;
		
		for(int i=0;i<count;i++)
		{
			StringTokenizer st = new StringTokenizer(stdin.readLine());
			m = getInt(st.nextToken());//100
			n = getInt(st.nextToken());//5
			sum = 0;
			while(m != 0){  
				m /= n;
				sum += m;
			}
			System.out.println(sum);
		}

	}

	private static int getInt(String str) 
	{
		return Integer.parseInt(str);
	}

}






     
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值