自幂数 C++ 代码进阶

自幂数最大位39,遍历是不可能的。根据性质,自幂数和数的大小与各个位数上的幂次和有关。遍历数需要10^{n}次,但如果是遍历各个位数上的幂次和呢,就是n^{10}了。

从0~9每个数字在这个数中都可能出现0~n次,就是n^{10}

那么,肯定有疑问了,10^{n}n^{10}以数字10为分阶线,前者十以内更小一点,可是我们连10位数都要跑好久,这样乍一看,还是要耗时好久,至少得个小半个小时。

所以这种遍历方法还有一个优势,就是剪枝。

1.每个数字的出现次数和等于n

2.一旦幂次和大于上限,continue

3.一旦幂次和(当前值+剩余次数*当前最大幂,有点难讲清楚,看代码吧)小于最小值,continue

如果还要更快一点,那就再来个记忆化搜索。

还有就是cout没法输出那么大的数,也不知道最大时多少,反正30位是不可能的。

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int aa[10],bb[10];
__int128 num[10];
__int128 max1,min1;

void print128(__int128 x)
{
	if(x == 0)	return ;
	print128(x / 10);
	putchar(x % 10 + '0');
}

void recursion(__int128 sum,int nowp,int less)
{
	if(less<0) return;
	if(nowp==0)
	{
		aa[0]=less;
		less=0;
	}
	if(sum+less*num[nowp]<min1) return;
	
	if(less==0)
	{
		__int128 sum1=sum;
		for(int i=0;i<10;i++) bb[i]=aa[i];
		while(sum1)
		{
			int ss=sum1%10;
			if(bb[ss]<=0) 
			{
				return;
			}
			bb[ss]--;sum1/=10;
		}
		print128(sum);cout<<" ";return;
	}
	for(int j=0;j<=less;j++)
	{
		aa[nowp]=j;
		if(sum+j*num[nowp]>max1) break;
		recursion(sum+j*num[nowp],nowp-1,less-j);
		aa[nowp]=0;
	}
}

int main()
{
	for(int i=1;i<=30;i++)
	{
		memset(aa,0,sizeof(aa));
		for(int j=0;j<10;j++)
		{
			num[j]=pow(j,i);
		}
		min1=pow(10,i-1);max1=10*min1-1;
		cout<<i<<"位数:";
		recursion(0,9,i);
		cout<<endl;
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值