LightOJ - 1189 - Sum of Factorials
先上题目
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 }