LIGHT OJ 1189 - Sum of Factorials【贪心+递归】

本文探讨了如何解决一个整数是否能表示为若干个不同阶乘数之和的问题,并提供了一种有效的贪心算法解决方案。通过对输入整数进行递归拆解,找到构成该整数的所有阶乘数。

1189 - Sum of Factorials

Time Limit: 0.5 second(s)Memory Limit: 32 MB

Given an integer n, you have to find whether it can be expressed as summation of factorials. For given n, you have to report a solution such that

n = x1! + x2! + ... + xn! (xi < xj for all i < j)

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 1018).

Output

For each case, print the case number and the solution in summation of factorial form. If there is no solution then print'impossible'. There can be multiple solutions, any valid one will do. See the samples for exact formatting.

Sample Input

Output for Sample Input

4

7

7

9

11

Case 1: 1!+3!

Case 2: 0!+3!

Case 3: 1!+2!+3!

Case 4: impossible

Note

Be careful about the output format; you may get wrong answer for wrong output format.


题意:N如果可以表示成某几个数的阶乘则找出这几个数,不能的话输出impossible,不能有x相同的的数;

思路:N达到lld的限度o(N)的复杂度都不行,不能打表所有数,但是可以打出阶乘的表因为20!>2*10^18,就19项就行了,那所有数的组合就是2^19,6位数打表能打,但是所有数之和加起来lld都存不了dp就pass了,只有一个一个判断喽, 了N要么直接就等于一个数的阶乘要么大于一个数的阶乘,等于的话直接记录这个数就行,如果大于的话,要组成阶乘的形式,必须要选这个数,如果不选,那么比这个数小的所有数的阶乘之和都不能取代这个数,这就是贪心选择了,每次找到一个<=N的最大的阶乘,然后用N减去这个阶乘形成了有一个N,递归判断就行;
失误:这题做了一天,想了好久想出来了阶乘的性质(N!>=0!+1!+...+(N-1)!   N=2时等号成立)但是一个递归把我难住了,写不好,又忽视了一个条件 就是不能有相同的,还是递归的条件考虑的不清楚,以后写递归时要注意了 (例如DFS);

AC代码:
#include<cstdio>
#include<cstring>

typedef long long LL;

LL a[33],ord[33],cnt=0;
bool vis[30];//一夜没睡状态不好 错误百出循环条件 数组名称 

bool solve(LL N)
{
	LL i=0;
	if(N==0) return true;
	for(i=19;i>=0;--i)
	{
		if(N>=a[i]&&!vis[i]) {
			break;
		}
	}
	if(i==-1) return false;//<=N的都选完了 N还不为0 
	ord[++cnt]=i;
	vis[i]=true;
	if(solve(N-a[i])) return true;
	return false;
}
int main()
{
	LL i,T,N,Kase=0;
	a[0]=1; for(i=1;i<=20;++i) a[i]=a[i-1]*i;
	scanf("%lld",&T);
	while(T--)
	{
		memset(vis,false,sizeof(vis)); 
		scanf("%lld",&N); cnt=0;
		printf("Case %lld: ",++Kase);
		if(solve(N)) {
			for(i=cnt;i>=1;--i)
			{
				if(i<cnt) printf("+");
				printf("%lld!",ord[i]);
			}
			printf("\n");
		}
		else {
			printf("impossible\n");
		}
	}
	return 0;
 } 


评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值