分解质因数
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。如30=2×3×5 。分解质因数只针对合数。
唯一分解定理:一个数n肯定能被分解成 n = p1{a1}p2{a2}…*pn^{an}. 因为一个数肯定是由合数和质数构成的,合数又可以分解成质数和合数,最后递归下去就会变成质数的乘积。
求出数n的因子个数
n = p1{a1}p2{a2}…*pn^{an}有一个很简洁的公式:
n的因子个数 = (1+a1)(1+a2)…(1+an)
题目链接:分解质因数1
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
printf("%d=",n);
for(int i=2;i*i<=n;i++)
{
while(n%i==0)
{
n=n/i;
printf("%d",i);
if(n!=1)
printf("*");
}
}
if(n!=1)
printf("%d\n",n);
}
题目链接:分解质因数2(Smith Numbers )
#include<stdio.h>
int s(int n)
{
int sum=0;
while(n)
{
sum+=n%10;
n=n/10;
}
return sum;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==0)
break;
//printf("%d=",n);
while(1)
{
n++;
int k=n;
int p=s(n);
int sum=0,f=1;
for(int i=2;i*i<=k;i++)
{
while(k%i==0)
{
k=k/i;
f=0;
sum=sum+s(i);
//printf("%d\n",i);
}
}
if(f)//n不能为素数
continue;
if(k!=1)
sum+=s(k);
// printf("%d %d\n",sum,n);
if(p==sum)
{
printf("%d\n",n);
break;
}
}
}
}
欧拉函数
就是对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n)
欧拉函数的定义:phi(n)=n*(1-p1)(1-p2)…*(1-pn)//p1,p2,pn为n的质因数
求单个数的欧拉函数
题目链接:POJ2407—Relatives
#include<stdio.h>
int main()
{
int n,i;
while(~scanf("%d",&n))
{
if(n==0)
break;
int p=n;//p的值即为n的欧拉函数
for(i=2;i*i<=n;i++)//下面要找n%i==0的i,在sqrt(n)之后就没有意义了
{
if(n%i==0)//找到一个质因数
{
p=(p/i)*(i-1);//相当于n*(1-1/p1)的展开
while(n%i==0)//保证这个因子完全除去
n=n/i; //还剩一个一次幂的因子
}
}
if(n>1)
p=(p/n)*(n-1);
printf("%d\n",p);
}
}
欧拉函数打表(求某个区间各个数的欧拉函数)
题目链接:LightOJ1007 Mathematically Hard
#include<stdio.h>
#include<string.h>
const int maxn= 5000001;
long long a[maxn];
void s()
{
memset(a,0,sizeof(a));
a[1]=1;//1的欧拉函数为本身
int i,j;
for(i=1;i<maxn;i++)//区间
{
if(a[i]==0)//找到每一个素数
{
for(j=i;j<maxn;j+=i)
{
if(a[j]==0)
a[j]=j;//相当于公式中的第一个数字n
a[j]=a[j]/i*(i-1);//如果j只能分解为i,此时的a[j]即为j的欧拉函数,但往往不是
//例如i=2是,a[6]=3(实则6的欧拉函数为2),
//当执行i=3时,再次执行,a[6]=3/3*(3-1)=2
//book[j]先/i再*(i-1)的目的,避免book[j]*(i-1)超数据范围
}
}
}
for(i=2;i<maxn;i++)//前缀和
a[i]=a[i-1]+a[i]*a[i];
}
int main()
{
s();
int t,l=1;
scanf("%d",&t);
while(t--)
{
int a1,b;
scanf("%d%d",&a1,&b);
printf("Case %d: ",l++);
printf("%llu\n",a[b]-a[a1-1]);
}
}
//%lu 是无符号长整型数据
题目链接:Farey Sequence
题解:当a和b互质时a/b为最简分数,设f(n)表示为小于n且与n互质的数的个数,那么易得F(n)=f(2)+f(3)+…+f(n),很容易知道 f(n) 就是欧拉函数,因此使用筛法打表,然后求前缀和即可。
#include<stdio.h>
#include<string.h>
const int maxn=1000010;
long long a[maxn];
void s()
{
memset(a,0,sizeof(a));
a[1]=1;
int i,j;
for(i=1;i<maxn;i++)
{
if(a[i]==0)
{
for(j=i;j<maxn;j+=i)
{
if(a[j]==0)
a[j]=j;
a[j]=a[j]/i*(i-1);
}
}
}
a[1]=a[2]=1;
for(i=2;i<maxn;i++)
a[i]=a[i-1]+a[i];
}
int main()
{
s();
int t,l=1,i;
int n;
while(~scanf("%d",&n))
{
if(n==0)
break;
printf("%lld\n",a[n]-1);
}
}
约瑟夫环
视频讲解链接:视频模拟
博客讲解链接:博客链接1
博客讲解链接 : 博客链接2
题目链接:And Then There Was One
一共有n个人,从第k个人开始报数,数到m的人出列,
#include<stdio.h>
int main()
{
int n,m,k,i;
while(~scanf("%d%d%d",&n,&m,&k))
{
int s=0;
if(n+m+k==0)
break;
for(i=2;i<n;i++)
s=(s+m)%i;
s=(s+k)%n;
printf("%d\n",s+1);
}
}
约瑟夫环的变形:
题目链接:Eeny Meeny Moo
#include<stdio.h>
int main()
{
int n,m,k,i,j;
while(~scanf("%d",&n)&&n)
{
int s=0;
for(i=1;;i++)
{
s=0;
for(j=2;j<n;j++)
s=(s+i)%j;
if(s==0)//因为是从0开始的,而且最后结果s+1+1==2
{
printf("%d\n",i);
break;
}
}
}
}