任何一个大于1的正整数都能唯一分解为有限个质数的乘积。
可以扫描2-sqrt(n)的每个数d,若d能整除N,则从N中除掉所有的因子d,同时累计除去d的个数。
//质因数分解试除法
void divide(int n)
{
m=0;
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
p[++m]=i;c[m]=0;
while(n%i==0)
{
c[m]++;
n/=i;
}
}
}
if(n>1)
p[++m]=n,c[m]=1;
}
题意:
给定两个整数L,R(1<=L<=R<=231,R-L<=106)。求闭区间[L,R]中相邻两个质数的差最大时多少,输出这两个质数。最小是多少,输出这两个质数。
思路:
可以看到虽然L,R的范围很大,但是R-L的范围却很小。所以不妨先将2- R \sqrt R R的质数筛出来。对于任意一对L-R,扫描素数p,标记i*p(L/p <= i<= R/p)
扫描结束后,没有被标记到的就是剩下的质数。
#include
#include
#include
#include
#include
#include
using namespace std;
const int INF=1e9;
const int maxn=5e4+10;
const int maxm=1e6+10;
int l,u,prime[maxn],vis[maxn],f[maxm],t;
void init()//求出50000内的素数,int范围内的合数最小质因子必定小于2^16。
{
int i,j,k,m;
t=0;
m=(int)sqrt(maxn+0.5);
memset(vis,0,sizeof(vis));
for(i=2;i<=m;i++)
{
if(!vis[i])
{
for(j=i*i;j<maxn;j+=i)
vis[j]=1;
}
}
for(i=2;i<maxn;i++)if(!vis[i])prime[t++]=i;
}
int main()
{
init();
while(cin>>l>>u)
{
if(l==1)l=2;//注意l=1会出问题。
int i,j,k,a,b;
memset(f,0,sizeof(f));
for(i=0;i<t;i++)
{
a=(l-1)/prime[i]+1;
b=u/prime[i];
for(j=a;j<=b;j++)if(j>1)f[j*prime[i]-l]=1;//[l,u]区间小于1e6,而l,u数值范围为int,所以偏移l们就能用数组存了
}
int p=-1,max_ans=-1,min_ans=INF,x1,y1,x2,y2;
for(i=0;i<=u-l;i++)//暴力枚举。。
{
if(f[i]==0)
{
if(p==-1){p=i;continue;}
if(max_ans<i-p){max_ans=i-p;x1=p+l;y1=i+l;}
if(min_ans>i-p){min_ans=i-p;x2=p+l;y2=i+l;}
p=i;
}
}
if(max_ans==-1)cout<<"There are no adjacent primes."<<endl;
else cout<<x2<<","<<y2<<" are closest, "<<x1<<","<<y1<<" are most distant."<<endl;
}
return 0;
}
题意:
给定整数N(1<=N<=10^6),试把阶乘N!分解质因数,按照算数基本定理的形式输出分解结果中的pi和ci即可。
思路:
可以先筛出1-N的素数,然后考虑N!阶乘中有多少个素数p。
N!中质因子p的个数等于1-N每个数包含质因子p的个数之和。
在1-N中,p的倍数,至少包含一个质因子p;
在1-N中,p^2的倍数,至少包含2个质因子p,但是在p的时候已经加过一个了,所以这里只需加1;
…
一直到 p^k<=N为止。limit等于 l o g p N log_p^N logpN
时间复杂度比O(Nlog(N))稍小。
#include
using namespace std;
#define ll long long
const int MAXN=1e6+10;
int prime[MAXN+1];
void getprime()
{
memset(prime,0,sizeof(prime));
for(int i=2;i<=MAXN;i++)
{
if(!prime[i])
{
prime[++prime[0]]=i;
}
for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++)
{
prime[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
int sum[MAXN+10];
int main()
{
int n;
getprime();
cin>>n;
for(int i=1;prime[i]<=n;i++)
{
int limit=log10(n)/log10(prime[i]);
for(int j=1;j<=limit;j++)
{
sum[prime[i]]+=(n/pow(prime[i],j));
}
}
for(int i=2;i<=MAXN;i++)
{
if(sum[i]!=0)
cout<<i<<" "<<sum[i]<<endl;
}
return 0;
}
LightOJ - 1236
题意:
求1=
思路:
n = p1 ^ e1 * p2 ^ e2 *…*pn ^ en
for i in range(1,n):
ei 从0取到ei的所有组合
必能包含所有n的因子。
现在取n的两个因子a,b
a=p1 ^ a1 * p2 ^ a2 *…*pn ^ an
b=p1 ^ b1 * p2 ^ b2 *…*pn ^ bn
gcd(a,b)=p1 ^ min(a1,b1) * p2 ^ min(a2,b2) *…*pn ^ min(an,bn)
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) *…*pn ^ max(an,bn)
先对n素因子分解,n = p1 ^ e1 * p2 ^ e2 *…*pk ^ ek,
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) *…*pk ^ max(ak,bk)
所以,当lcm(a,b)==n时,max(a1,b1)==e1,max(a2,b2)==e2,…max(ak,bk)==ek
当ai == ei时,bi可取 [0, ei] 中的所有数 有 ei+1 种情况,bi==ei时同理。
那么就有2(ei+1)种取法,但是当ai = bi = ei 时有重复,所以取法数为2(ei+1)-1=2ei+1。
除了 (n, n) 所有的情况都出现了两次 那么满足a<=b的有 (2ei + 1)) / 2 + 1 个
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=1e7+5;
const int NN=1e6;
unsigned int prime[NN],cnt; //prime[N]会MLE
bool vis[N];
void is_prime()
{
cnt=0;
memset(vis,0,sizeof(vis));
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
for(int j=i+i;j<N;j+=i)
{
vis[j]=1;
}
}
}
}
int main()
{
is_prime();
int t;
cin>>t;
for(int kase=1;kase<=t;kase++)
{
LL n;
cin>>n;
int ans=1;
for(int i=0;i<cnt&&prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
int e=0;
while(n%prime[i]==0)
{
n/=prime[i];
e++;
}
ans*=(2*e+1);
}
}
if(n>1)
ans*=(2*1+1);
printf("Case %d: %d\n",kase,(ans+1)/2);
}
}