51nod1016 水仙花数 V2(打表)

题目
夹克爷的远古帖上有打表的方法,但两份代码一个C#,一个java,懒得看
水仙花数的个数是有限的,位数最多39位,不知道怎么证,反正跑出来的结果是这样的
我是自己打的表,本机大概运行13s可跑出来
具体方法就是:枚举水仙花数中 1 − 9 1-9 19的个数,剩下的位填 0 0 0,这样就能计算出水仙花数,判断 1 − 9 1-9 19的个数是否与枚举的一样即可
9 9 9 1 1 1枚举可以优化
我有三个剪枝(假设当前每个数 n n n次方的和为 s s s,当前填到 x x x):
1. 1. 1.如果 s s s的位数已经 > n >n >n,那么 r e t u r n return return
2. 2. 2.如果剩下的数全填最大的还不到 n n n为,那么 r e t u r n return return
3. 3. 3.如果剩下的数全填最大的前几位与 s s s对应位相同,那么这几位一定不会变了,而每个数的个数是从大到小枚举的,所以那些大于 x x x的数的个数不会增加,但如果前几位中有大于 x x x的数的个数大于枚举出这个数字应该出现个数,那么 r e t u r n return return,具体见代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e9;
struct NUM{//压位高精
	int t;ll a[10];
	friend NUM operator+(NUM x,NUM y){
		int i;
		for (i=0;i<x.t || i<y.t || x.a[i];i++){
			if (i+1>=x.t) x.a[i+1]=0;
			if (i<y.t) x.a[i]+=y.a[i];
			if (x.a[i]>=M) x.a[i+1]++,x.a[i]-=M;
		}
		x.t=i;
		return x;
	}
	friend NUM operator*(NUM x,int y){
		int i;
		for (i=0;i<x.t;i++) x.a[i]*=y;
		for (i=0;i<x.t || x.a[i];i++){
			if (i+1>=x.t) x.a[i+1]=0;
			x.a[i+1]+=x.a[i]/M,x.a[i]%=M;
		}
		x.t=i;
		return x;
	}
}f[11][42],s;//f[i][j]=i^j
int n,a[10],c[10],d[10],t1,t2,n1[50],n2[50];
void dfs(int x,int y,NUM s){
	t2=0;
	memset(c,0,sizeof(c));
	for (int i=0;i<s.t;i++){
		int t=s.a[i];
		for (int j=0;j<9;j++) c[n2[t2++]=t%10]++,t/=10;
	}
	while (t2 && !n2[t2-1]) t2--;
	if (t2>n) return;
	t1=0;
	NUM tmp=s+f[x][n]*(n-y);//最大能得到的数
	for (int i=0;i<tmp.t;i++){
		int t=tmp.a[i];
		for (int j=0;j<9;j++) n1[t1++]=t%10,t/=10;
	}
	while (t1 && !n1[t1-1]) t1--;
	if (t1<n) return;
	if (x && t1==t2){
		memset(d,0,sizeof(d));
		for (int i=n-1;~i;i--)
			if (n1[i]!=n2[i]) break;
			else d[n1[i]]++;
		for (int i=x+1;i<=9;i++)
			if (a[i]<d[i]) return;
	}
	if (!x){
		for (int i=1;i<=9;i++)
			if (a[i]!=c[i]) return;
		for (int i=t2-1;~i;i--) putchar(n2[i]|48);
		puts("");
		return;
	}
	for (int i=0;i<=n-y;i++){
		a[x]=i;
		dfs(x-1,y+i,s);
		s=s+f[x][n];
	}
}
int main(){
	puts("0");
	for (int i=1;i<10;i++){
		f[i][0].t=f[i][0].a[0]=1;
		for (int j=1;j<42;j++) f[i][j]=f[i][j-1]*i;
	}
	for (int i=1;i<=39;i++) n=i,dfs(9,0,s);
}

这是交上去的代码:

#include<bits/stdc++.h>
using namespace std;
string s,t[]={"153","370","371","407","1634","8208","9474","54748","92727","93084","548834","1741725","4210818","9800817","9926315","24678050","24678051","88593477","146511208","472335975","534494836","912985153","4679307774","32164049650","32164049651","40028394225","42678290603","44708635679","49388550606","82693916578","94204591914","28116440335967","4338281769391370","4338281769391371","21897142587612075","35641594208964132","35875699062250035","1517841543307505039","3289582984443187032","4498128791164624869","4929273885928088826","63105425988599693916","128468643043731391252","449177399146038697307","21887696841122916288858","27879694893054074471405","27907865009977052567814","28361281321319229463398","35452590104031691935943","174088005938065293023722","188451485447897896036875","239313664430041569350093","1550475334214501539088894","1553242162893771850669378","3706907995955475988644380","3706907995955475988644381","4422095118095899619457938","121204998563613372405438066","121270696006801314328439376","128851796696487777842012787","174650464499531377631639254","177265453171792792366489765","14607640612971980372614873089","19008174136254279995012734740","19008174136254279995012734741","23866716435523975980390369295","1145037275765491025924292050346","1927890457142960697580636236639","2309092682616190307509695338915","17333509997782249308725103962772","186709961001538790100634132976990","186709961001538790100634132976991","1122763285329372541592822900204593","12639369517103790328947807201478392","12679937780272278566303885594196922","1219167219625434121569735803609966019","12815792078366059955099770545296129367","115132219018763992565095597973971522400","115132219018763992565095597973971522401"};
int i;int main(){for(cin>>s;i<79;i++)if (t[i].size()==s.size()?t[i]>s:t[i].size()>s.size()) return cout<<t[i],0;puts("No Solution");}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值