阶乘的和(上交考研机试 + 01背包 / 状压枚举 )

原题链接
思路分析:
原题问 n n n 是否可以被表示成若干个阶乘的和,需要注意的是 0 ! = 1 0!=1 0!=1
例如 4 4 4 就可以被 0 !    +    1 !    + 2 !    0!\;+\;1!\;+2!\; 0!+1!+2! 正确表示出来。
发现每个阶乘可以选或者不选,联想到 01 01 01 背包。
预处理出所有情况即可。

此外对于选或者不选的方案可能,可通过状压枚举获得和的所有情况。

C o d e : Code: Code:

// 01背包
#include 
using namespace std;
typedef long long LL;
const int N = 15, M = 1000010;
LL A[N];
bool dp[M];
signed main(){
     
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    A[0] = 1;
    for(int i = 1; i <= 10; i++){
     
        A[i] = 1ll * A[i-1] * i;
    }
    
    dp[0] = true;
    for(int i = 0; i <= 10; i++){
     
        for(int j = 1000000; j >= A[i]; j--){
     
            dp[j] |= dp[j-A[i]];
        }
    }
    
    LL n;
    while( cin >> n && n >= 0 ){
     
        if( dp[n] && n > 0 ){
     
            cout << "YES" << '\n';
        }
        else{
     
            cout << "NO" << '\n';
        }
    }
    
    return 0;
}
//状压枚举
#include 
using namespace std;
#define MaxN 15
typedef long long LL;
LL A[MaxN];
unordered_set <LL> S;
signed main(){
     
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    A[0] = 1;
    for(int i = 1; i < 10; i++){
     
        A[i] = 1ll * A[i-1] * i;
    }
    
    for(int i = 1; i < 1 << 10; i++){
     
        LL C = 0;
        for(int j = 0; j < 10; j++){
     
            if( i >> j & 1 ){
     
                C += A[j];
            }
        }
        S.insert(C);
    }
    
    LL n;
    while( cin >> n && n >= 0 ){
     
        if( S.count(n) ){
     
            cout << "YES" << '\n';
        }
        else{
     
            cout << "NO" << '\n';
        }
    }
    
    return 0;
}

你可能感兴趣的:(题解)