HDU2683——欧拉完全数

题目要求符合等式的数,我们首先要做的就是分析这个数:

在这里插入图片描述

对于这个等式,我们可能什么都看不出来,左边很难化简的样子,所以我们就要想到通过变化怎么样把右边化成和左边形式差不多的样子。结合组合数我们想到二项式定理,展开得到
在这里插入图片描述
左边等于右边的话我们可以得到g(n)=2*n,因为n本身为自身的因子,那么n的小于自身的因子之和为自身说明n为完全数。
所以问题转换为如何求完全数。
由数论知识得任何一个完全数都可以写成 2p-1 *(2p-1)的形式,其中(2p-1)为素数(也叫做梅森素数)
梅森素数的条件为p为素数。
由以上(我靠比赛我到哪去找这些知识点),我们可以找到所有的完全数(其实也没有几个)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<set>
#include<vector>

using namespace std;

typedef long long ll;
const int MAXN=1e5+5;

ll mult(ll x,ll y,ll  p)
{
	long double d=1;
	d=d*x/p*y; return ((x*y-((ll)d)*p)%p+p)%p;
}

ll quick_pow(ll a,ll b,ll p)
{
	ll ret=1; a%=p;
	while(b)
	{
		if(b&1) ret=mult(ret,a,p);
		a=mult(a,a,p); b>>=1;
	}
	return ret;
}


bool Miller_Rabin(ll n)
{
	const ll times=8;
	const ll prime[8]={2,3,5,7,11,13,17,61};
	
	if(n<2) return false; if(n==2) return true;
	for(int i=0;i<times;i++)
	if(n==prime[i]) return true; else if(!(n%prime[i])) return false;
	ll x=n-1; while(!(x&1)) x>>=1;
	for(int i=0;i<times;i++)
	{
		ll a=prime[i]; ll now=quick_pow(a,x,n); ll last;
		if(x==n-1)
		{
			if(now!=1) return false;
		}
		else
		{
			bool flag=false;
			while(x!=n-1)
			{
				last=now;  now=mult(now,now,n);
				if(now==1)
				{
					if(last==n-1 || last==1) flag=true; break;
				}
				x<<=1;
			}
			if(!flag) return false;
		}
	}
	return true;
}

ll quick_pow(ll a,ll b)
{
	ll ret=1;
	while(b)
	{
		if(b&1) ret*=a;
		a*=a; b>>=1;
	}
	return ret;
}

const int prime[11]={2,3,5,7,11,13,17,19,23,29,31};

int main()
{
/*
	for(int i=0;i<11;i++)
	{
		ll t=quick_pow(2,prime[i]);
		ll a=t-1;
		//printf("a=%lld t=%lld \n",a,t);
		if(Miller_Rabin(a))
		{
			t/=2; printf("%lld\n",t*a);
		}
	}
	//找到的所有的完全数
	6
	28
	496
	8128
	33550336
	8589869056
	137438691328
	2305843008139952128
*/

	char cmd[5]; ll a,b;
	const ll ans[8]={6,28,496,8128,33550336,8589869056,137438691328,2305843008139952128};
	while(~scanf("%s",cmd))
	{
		if(cmd[0]=='A')
		{
			scanf("%lld%lld",&a,&b);
			if(b<a) swap(a,b);
			int cnt=upper_bound(ans,ans+8,b)-lower_bound(ans,ans+8,a);
			printf("%d\n",cnt);
		}
		else
		{
			scanf("%lld",&a);
			printf("%d\n",upper_bound(ans,ans+8,a)-lower_bound(ans,ans+8,a));
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值