LightOJ - 1189 - Sum of Factorials

先上题目

Sum of Factorials
                  Time Limit:500MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu

Description

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

4

7

7

9

11

Sample Output

Case 1: 1!+3!

Case 2: 0!+3!

Case 3: 1!+2!+3!

Case 4: impossible

Hint

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

 

  这一题题意就是给你一个数,问哪些数的阶乘等于这个数,并按照样例从小到大输出这些数的每一项,其中每一项只可以用一次,如果不存在这些数,就输出impossible。

      一开始看的时候第一个想到的是用dfs,然后就很轻松地写出的代码,可是发现样例的第四个case卡住了很久,然后就加了一个约束条件,不过时间复杂度还是比较大,跑10个case还是要10ms,而题目要求仅有500ms,于是想了很久怎样优化,看榜发现很多人都很快过了这题,心里有点急,可是心越急就越想不出来,后来干脆把这题丢到一边,想其他题,后来又过了一题以后就继续这题,因为题目要求的数据范围是1~10^18,用longlong不会爆,而且这时才想起阶乘数的一个特征,相邻两项的差距是越来越大的,某一个数的前面所有数的和加起来也不够这个数大,于是就以这个为策略使用贪心算法,结果代码不长,然后wa了一次,检查发现是打表数字打错了,= =。后来听人家说这一题我们是做过的,所以其他人才过的这么快,= =。看来以后做完题目要总结一下。

 

上代码:

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <map>
 4 #define MAX 10000
 5 using namespace std;
 6 
 7 long long p[21]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000,6402373705728000,121645100408832000,2432902008176640000};
 8 bool mark[21];
 9 
10 bool check(long long n,int q)
11 {
12     if(n==0) return 1;
13     int i;
14     for(i=q;i>=0;i--)
15     {
16         if(n>=p[i]) break;
17     }
18     q=i;
19     if(mark[q]) return 0;
20     mark[q]=1;
21     if(check(n-p[q],q-1)) return 1;
22     mark[q]=0;
23     return 0;
24 }
25 
26 
27 
28 
29 int main()
30 {
31     //freopen("data.txt","r",stdin);
32     int i,j,t,c;
33     long long n;
34     scanf("%d",&t);
35     for(i=1;i<=t;i++)
36     {
37         scanf("%lld",&n);
38         memset(mark,0,sizeof(mark));
39         printf("Case %d: ",i);
40         if(!check(n,20)) printf("impossible\n");
41         else
42         {
43             c=0;
44             for(j=0;j<=20;j++)
45             {
46                 if(mark[j])
47                 {
48                     if(c++) printf("+");
49                     printf("%d!",j);
50                 }
51             }
52             printf("\n");
53         }
54     }
55 
56     return 0;
57 }
1189

 

转载于:https://www.cnblogs.com/sineatos/p/3221476.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值