PC/UVa 题号: 110704/10139 Factovisors

两个数 n 和 k 判断k能否整除 n!

思路:

任何一个正整数 n=p1^(x1)*p2^(x2)……*pn^(xn); 其中p1,p2.……pn 是素数,x1,x2,……xn 是各个素数的指数(也就是该质因数的个数)

将k分解质因数,并记录各个质因数的个数

分别用 2……n的数去除以k的质因数,每除一次就使k的质因数的个数减一,直到为零,最后遍历记录k的质因数个数的数组,只要有大于零的,就表示k不能整除n!

到这里基本上都对了,但是要注意的是,

1 数据范围是2^31 不是2^31-1 所以会发生溢出,要用大一点的类型,我用的是unsigned;

2 要注意 当k==0的时候是不能够整除任何数的

3 当k<=n时一定可以整除n!

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
unsigned num[1000];
unsigned num1[1000];
unsigned n,m;
int totle;
void getPrim(unsigned n)
{
 memset(num,0,sizeof(num));
 memset(num1,0,sizeof(num1));
 unsigned i;
 totle=0;
 if(n%2==0)
 {
  num[totle]=2;
  while(n%2==0)
  {
   n/=2;
   num1[totle]++;
  }
  totle++;
 }
 i=3;
 while(i<=((unsigned)sqrt((double)n)+1))
 {
  if(n%i==0)
  {
   num[totle]=i;
   while(n%i==0)
   {
    num1[totle]++;
    n/=i;
   }
   totle++;
  }
  i+=2;
 }
 if(n>1)
 {
  num[totle]=n;
  num1[totle]++;
  totle++;
 }
}
int jugde(unsigned n,unsigned m)
{
 if(((n==1||n==0)&&m>1)||m==0)
 {
  printf("%d does not divide %d!\n",m,n);
  return 1;
 }
 else if(m<=n)
 {
  printf("%d divides %d!\n",m,n);
  return 1;
 }
 return 0;
}
unsigned solve(int n)
{
 unsigned i,j;
 long s=1,t;
 for(i=0;i<totle;i++)
 {
  for(j=num[i];j<=n;j+=num[i])
  {
   t=j;
   while(t%num[i]==0&&num1[i]>0)
   {
    num1[i]--;
    t/=num[i];
   }
   while(s%num[i]==0&&num1[i]>0)
   {
    s/=num[i];
    num1[i]--;
   }
   if(t!=j)
     s*=t;
  }
 }
 for(i=0;i<totle;i++)
  if(num1[i]>0) return 0;
  return 1;
}
int main()
{
 unsigned t;
 while(scanf("%d%d",&n,&m)!=EOF)
 {
  if(jugde(n,m)) continue;
  getPrim(m);
  t=solve(n);
  if(t==0)
   printf("%d does not divide %d!\n",m,n);
  else
   printf("%d divides %d!\n",m,n);
 }
 return 0;
 
}

 


还有一个定理: n!中某一素数p的个数sum

for(i=p;i<=n;i*=p)

{

sum+=n/i;

}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
long num[100],num1[100];
long n,k,l;
long jugdeNum(long n,long numi)
{
 long i,sum;
 sum=0;
 for(i=numi;i<=n;i*=numi)
  sum+=n/i;
 return sum;
}
void getPriem(unsigned numa)
{
 l=0;
 memset(num,0,sizeof(num));
 memset(num1,0,sizeof(num1));
 long i,j=0;
 if(numa%2==0)
 {
  while(numa%2==0)
  {
   num1[j]++;
   numa/=2;
  }
  num[j]=2;
  j++;
 }
 i=3;
 while(i<=((unsigned)sqrt((double)numa)+1))
 {
  if(numa%i==0)
  {
   while(numa%i==0)
   {
    num1[j]++;
    numa/=i;
   }
   num[j]=i;
   j++;
  }
  i+=2;
 }
 if(numa>1)
 {
  num[j]=numa;
  num1[j]=1;
  j++;
    }
 l=j;
}
int main()
{
 unsigned i;
 while(scanf("%ld%ld",&n,&k)!=EOF)
 {
  if(k==0||((n==0||n==1)&&k>1))
  {
   printf("%ld does not divide %ld!\n",k,n);
   continue;
  }else if(k<=n)
  {
   printf("%ld divides %ld!\n",k,n);
   continue;
  }
  getPriem(k);
  int flag=0;
  for(i=0;i<l;i++)
   if(jugdeNum(n,num[i])<num1[i])
   {
    flag=1;
    break;
   }
   if(flag==1)
    printf("%ld does not divide %ld!\n",k,n);
   else
    printf("%ld divides %ld!\n",k,n);
 }
 return 0;
 
}

这个看起来比较简单

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值