质数
【例题】Prime Distance(poj2689)
这题L,R范围很大,但是L,R差值在可以接受的范围内。因为一个数n的质因子不会超过
,所以我们考虑线筛预处理
范围内所有的质数,在线筛的的同时标记L到R范围的合数。
如何标记:对每一个质数p,枚举一个倍数i,将i*p标记为合数。i的范围是
(因为
)。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int pri[50010],pr;
bool v[50010];
void get_prime(int n)
{
memset(v,true,sizeof(v));
pr=0;
for(int i=2;i<=n;i++)
{
if(v[i]) pri[++pr]=i;
for(int j=1;(j<=pr)&&(i*pri[j]<=n);j++)
{
v[i*pri[j]]=false;
if(i%pri[j]==0) break;
}
}
}
bool f[1000010];
int main()
{
int L,R;
get_prime(50000);
while(scanf("%d%d",&L,&R)!=EOF)
{
if(L==1) L=2;
memset(f,true,sizeof(f));
for(int i=1;i<=pr;i++)
{
int l=(L-1)/pri[i]+1;
int r=R/pri[i];
for(int j=l;j<=r;j++)
if(j>1)
f[j*pri[i]-L]=false;
}
int last=-1,maxx=-1,minn=2147483647,a,b,c,d;
for(int i=0;i<=R-L;i++)
{
if(f[i])
{
if(last==-1){last=i; continue;}
if(i-last<minn)
{
minn=i-last;
a=last+L,b=i+L;
}
if(i-last>maxx)
{
maxx=i-last;
c=last+L,d=i+L;
}
last=i;
}
}
if(maxx==-1) puts("There are no adjacent primes.");
else printf("%d,%d are closest, %d,%d are most distant.\n",a,b,c,d);
}
return 0;
}
【例题】阶乘分解(传送门)
本题前提是阶乘,所以所有小于N的数都会出现,那么
中质因子的个数就等于1~N每个数的质因子个数之和。假设质数p,在1~N中,至少包含一个质因子p(也就是分解质因数中有
)的数有
个(因为p在N范围内的倍数有这么多个),同理至少包含两个质因子p(也就是分解质因数中有
)的数有
个,那么对于每个质数p,N!中质因数p的个数为
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int pri[1000010],pr;
bool v[1000010];
int n;
void get_prime()
{
memset(v,true,sizeof(v)); pr=0;
for(int i=2;i<=n;i++)
{
if(v[i]) pri[++pr]=i;
for(int j=1;(j<=pr)&&(i*pri[j]<=n);j++)
{
v[i*pri[j]]=false;
if(i%pri[j]==0) break;
}
}
}
int main()
{
scanf("%d",&n);
get_prime();
for(int i=1;i<=pr;i++)
{
printf("%d ",pri[i]);
ll p=(long long)pri[i],sum=0;
while(p<=n)
{
sum+=n/p;
p*=pri[i];
}
printf("%lld\n",sum);
}
return 0;
}
约数
【例题】反素数ant(BZOJ1053)
这道题需要几个实用的引理和思维方式。
1、1~N中最大的反素数,就是1~N中约数最多的数中最小的那个
证明:因为约数最多的数中最小保证比他小的数约数都没有比他更多的,满足了他是“反素数”。且在比他大的数中约数个数最多都不会超过他,满足了“最大”。
思维方式:我们可以从反素数和最大两个特征去寻找这样的数,这同样可以用在其他类似的问题上。
2、1~N(
)中任意的数的质因子不会超过10个,且所有的质因子的指数总和不会超过30
证明:把最小的11个质数乘起来都已经超过了
,且最小的质数2的31次方也已经大于
。
思维方式:这个方法是常用的约数类问题突破口,抓住质因数比比较少且指数也比较少这一点可以通过搜索来组成一个数的约数。
3、反素数的必要条件是,他的质因子是连续的若干个最小的质因数,且指数单调递减
证明:反证法,如果存在一个反素数
的质因数分解中存在一项
,那么因为引理2所以他一定不被一个小于等于29的质数整除,设这个质数数为
,所以设
(也就是把x里面的
替换成
),这样所得的
但是
的约数个数等于
,所以
就不是一个反素数了。
思维方式:这里从反证法的思路去证明猜想。
所以我们根据引理2搜索出前十个质数的指数,并满足引理3,且同时记录约数个数,每当搜出一个满足条件的整数时用引理1去记录答案。因为有引理2的保证,算法速度快的且代码简洁。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int ans=-1,num=-1,n;
int pri[]={1,2,3,5,7,11,13,17,19,23,29,31};
void dfs(int k,ll now,int cnt,int last)
{
if(k==11)
{
if(cnt>num || (now<=ans && cnt>=num))
ans=now,num=cnt;
return;
}
int t=1;
for(int i=0;i<=last;i++)
{
dfs(k+1,now*t,cnt*(i+1),i);
t*=pri[k];
if(now*t>n) break;
}
return;
}
int main()
{
scanf("%d",&n);
dfs(1,1,1,20);
printf("%d\n",ans);
return 0;
}
【例题】余数之和(BZOJ1257)
非常有趣的一题。我们要计算
,mod运算肯定不好直接计算,我们把mod先化成
,那么原题目就转化为计算
。