题意描述

  • 给你一个数n,问能否用几个数的阶乘的和组成n,每一个数的阶乘只能够用一次

思路:

把0~9的阶乘打表打出来,每一个只能选一次,这不就是01背包问题啊,每一个只能用一次,n就是最大背包容量,跟这一次选拔赛那个D题几乎一样既可以01背包、也可以二进制枚举。我真的服了,当时为啥不好好读题呢。回到这里,这个题同样也可以采用二进制枚举的方法,求出每一种情况的和,丢进哈希表里,然后查询n是否在哈希表中。

二进制枚举
> 二进制的每一位都可以代表一种状态,选择或者不选择,那么每一个二进制数都代表一种情况。

二进制枚举代码

#include <iostream>
#include <unordered_set>
using namespace std;
const int N=1e6+10;

int n;
int a[10];
unordered_set<int> hh;

int main()
{
    a[0]=1;
    a[1]=1;
    for (int i=1;i<=9;i++) a[i]=a[i-1]*i;
    for (int i=0;i<1<<10;i++)
    {
        int t=0;
        for (int j=0;j<10;j++)
            if (i>>j&1) t+=a[j];
        hh.insert(t);
    }
    while (cin>>n)
    {
        if (n<0) break;
        if (!n)
        {
            cout<<"NO"<<endl;
            continue;
        }
        if (hh.count(n)) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

01背包代码

#include <iostream>
#include <unordered_set>
using namespace std;
const int N=1e6+10;

int n;
int a[10];
bool f[N];

int main()
{
    a[0]=1;
    a[1]=1;
    for (int i=1;i<=9;i++) a[i]=a[i-1]*i;

    int k=10;
    f[0]=true;
    for (int i=0;i<k;i++)
    {
        for (int j=N;j>=a[i];j--)
        {
            f[j]=f[j-a[i]]||f[j];
        }
    }
    while (cin>>n)
    {
        if (n<0) break;
        if (!n)
        {
            cout<<"NO"<<endl;
            continue;
        }

        if (f[n]) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}