分解质因子,欧拉函数,约瑟夫环

分解质因数

每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。如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;
		
		}
		}
		
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值