题意描述
- 给你一个数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; }