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 canbe expressed as summation of factorials. For givenn, you have to reporta solution such that

n = x1!+ x2! + ... + xn! (xi < xj forall 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 insummation of factorial form. If there is no solution then print'impossible'.There can be multiple solutions, any valid one will do. See the samples forexact 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 answerfor wrong output format.


第一思想肯定是枚举,然而可以非连续,,,DFS数据又很大,,,

除非找到阶乘的一个很重要的性质就是当前值的阶乘大于  小于他的数的阶乘和,这个规律,,不然很难会想到用贪心做因为无法判断所有情况,,,

数学+规律的推导技能


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

思路:N达到lld的限度o(N)的复杂度都不行,不能打表所有数,但是可以打出阶乘的表因为20!>2*10^18,就19项就行了,那所有数的组合就是2^19,6位数打表能打,但是所有数之和加起来lld都存不了dp就pass了,只有一个一个判断喽, 了N要么直接就等于一个数的阶乘要么大于一个数的阶乘,等于的话直接记录这个数就行,如果大于的话,要组成阶乘的形式,必须要选这个数,如果不选,那么比这个数小的所有数的阶乘之和都不能取代这个数,这就是贪心选择了,每次找到一个<=N的最大的阶乘,然后用N减去这个阶乘形成了有一个N

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
LL flag[30];
int ans[30];


int main()
{
    flag[0]=flag[1]=1;
    for(int i=2;i<=22;i++)
    {
        flag[i]=flag[i-1]*i;
    }
    int t, ncase=1;
    scanf("%d", &t);
    while(t--)
    {
        LL x;
        scanf("%lld", &x);
        for(int i=0;i<=22;i++)
        {
            if(x<flag[i])
            {
                printf("Case %d: impossible\n",ncase++);
                break;
            }
            int cnt=0, res=0;
            LL y=x;
            for(int j=i;j>=0;j--)
            {
                if(y>=flag[j])
                {
                    y-=flag[j];
                    ans[cnt++]=j;
                }
                if(y==0)
                {
                    res=1;
                    printf("Case %d: %d!",ncase++,ans[cnt-1]);
                    for(int k=cnt-2;k>=0;k--)
                    {
                        printf("+%d!",ans[k]);
                    }
                    printf("\n");
                    break;
                }
            }
            if(res==1)
            {
                break;
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值