You will get a non-negative integer n (n≤1,000,000) from input file.
For the n in the input file, you should print exactly one word ("YES" or "NO") in a single line. No extra spaces are allowed.
9 2
YES YES
#include<iostream> using namespace std; int main(){ int n; int a[11]; for(int i=1;i<11;i++){ if(i==1) a[i]=1; else a[i]=i*a[i-1]; } while(cin>>n){ for(int i=10;i>0;i--){ if(n>=a[i]) n-=a[i]; } if(n>1){ cout<<"NO"<<endl; } else cout<<"YES"<<endl; } }
while True: try: num = int(input()) factor = [1]*10 for i in range(2,10): #因为输入最大1000000,所以前十个阶乘就可以了 factor[i] = factor[i-1]*i index = 9 while index >= 0: #一直减,能减就减,因为阶乘大于其前面所有阶乘的和 if num >= factor[index]: num -= factor[index] index -= 1 if num == 0: #如果减空了说明能分解为阶乘之和 print('YES') else: print('NO') except Exception: break
#include<stdio.h>//依题之意判断n是否等于连续的阶乘和 int main()//10的阶乘为3628800,n一定小于10的阶乘,所以算出10以前的阶乘即可 { int n,i,a[10];//a[i]代表i的阶乘 a[0]=1; for(i=1;i<10;i++)//求1-9的阶乘 a[i]=a[i-1]*i; while(scanf("%d",&n)!=EOF) { for(i=9;i>=0;i--)//添加一个n==0时结束循环的语句也可以 if(n>=a[i]) n-=a[i]; if(n==0) printf("YES\n"); else printf("NO\n"); } }
#include<iostream> using namespace std; int main() { int n,a[10]; a[0] = 1; for(int i=1;i<=10;i++) a[i] = a[i-1]*i; while(cin>>n) { if(n==0) cout<<"NO"<<endl; for(int i=10;i>=0;i--) { if(n>=a[i]) n-=a[i]; } if(n==0) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
能减就减,因为n!一定大于前n - 1个数的阶乘的和
#include<iostream>
using namespace std;
int f[10];
int main(){
f[0] = 1;
for(int i = 1; i < 10; i++)
f[i] = f[i - 1] * i;
int n;
while(cin >> n){
for(int i = 9; i >= 0; i--){
if(n >= f[i]){
n -= f[i];
}
}
if(n == 0){
cout << "YES" << endl;
}
else{
cout << "NO" << endl;
}
}
return 0;
}
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int fact[10];
fact[0] = fact[1] = 1;
for(int i=2;i<10;i++)
{
fact[i] = fact[i-1]*i;
}
bool seq[1000001];
for(int i=0;i<=1000000;i++)
{
seq[i] = false;
}
for(int i=0;i<1024;i++)
{
int t = i;
int sum = 0;
for(int i=0;i<10;i++)
{
if(t%2==1)
sum += fact[i];
t /= 2;
}
seq[sum]=true;
}
int n;
cin >> n;
if(seq[n]==true)
cout << "YES";
else
cout << "NO";
return 0;
}
其实就是先把所有可以表示的数算出来。一共就10个元素,所有的组合算出来也就2^10个数需要算,每一种组合都可以用0(或1)——1023中的一个数表示。
//用递归写的 #include<iostream> using namespace std; #include<vector> vector<int> fac; void init(){ int t=1; fac.push_back(t); for(int i=1;t<=1000000;i++){ t *= i; fac.push_back(t); } } bool solve(int m, int maxf){ if(m==0)return true; else if(m<0)return false; if(maxf<0)return false; return solve(m-fac[maxf],maxf-1) || solve(m,maxf-1); } int main(){ int num; init(); while(cin>>num){ int maxf=fac.size(); while(fac[maxf]>num) maxf--; cout<<(solve(num,maxf)?"YES":"NO")<<endl; } }
#include <iostream>
using namespace std;
int main() {
int n, i;
int a[11];
a[0] = 1;
for (int i = 1; i <= 10; i++) {
a[i] = a[i - 1] * i;
}
while (cin >> n) {
for (int i = 10; i >= 0; i--) {
if (n >= a[i]) {
n -= a[i];
}
}
if (n > 0) {
cout << "NO" << endl;
}
else {
cout << "YES" << endl;
}
}
return 0;
}
#include <stdio.h> (737)#include <string.h> const int N = 1000000; const int M = 11; int n; int fact[M]; int maxIndex = 0; bool ans = false; void DFS(int curIndex,int sum) { if(curIndex > maxIndex || sum + fact[curIndex] > n) return; if(sum + fact[curIndex] == n){ ans = true; return; } DFS(curIndex+1,sum + fact[curIndex]); DFS(curIndex+1,sum); } int main() { scanf("%d",&n); fact[0] = 1; while(maxIndex < M && fact[maxIndex] <= n) { maxIndex++; fact[maxIndex] = fact[maxIndex-1] * maxIndex; } DFS(0,0); char str[5]; if(ans) strcpy(str,"YES"); else strcpy(str,"NO"); printf("%s",str); return 0; }
#include <stdio.h> (737)#include <string.h> const int N = 1000000; const int M = 11; int n; int fact[M]; int maxIndex = 0; bool dp[N]; bool ans = false; void bag() { dp[0] = true; for(int i = 0; i <= maxIndex; i++) for(int j = n; j >= fact[i]; j--) if(dp[j] == true || dp[j - fact[i]] == true) dp[j] =true; } int main() { scanf("%d",&n); fact[0] = 1; while(maxIndex < M && fact[maxIndex] <= n) { maxIndex++; fact[maxIndex] = fact[maxIndex-1] * maxIndex; } bag(); ans = dp[n]; char str[5]; if(ans) strcpy(str,"YES"); else strcpy(str,"NO"); printf("%s",str); return 0; }
#include <iostream> #include<vector> using namespace std; int main() { //这里其实是使用的是暴力搜索,先创建一个数组用来存储1-10的阶乘的结果, //由于10!已经是大于1000000了,因此其已经够对于n的值的搜索 //这里注意0!=1,这里是可以使用的如:4=0!+1!+2!,因此输出为YES vector<int>dp(11); dp[0] = 1; for (int i = 1; i <= 10; i++) { dp[i] = dp[i - 1] * i; } int n; while (cin >> n) { for (int i = 10; i >= 0; i--) { if (n >= dp[i]) n = n - dp[i]; if (n == 0) { cout << "YES" << endl; break; } } if (n != 0)cout << "NO" << endl; } }
#include <bits/stdc++.h> using namespace std; // 转换成01背包问题 // 求xi的阶乘 int xi(int n) { int sum = 1; for(int i=1;i<=n;++i) { sum *= i; } return sum; } int main() { int n; while(cin >> n && n != 0) { vector<int> dp(n+1, 0); for(int i=0;xi(i)<=n;++i) { for(int j=n;j>=xi(i);--j) { dp[j] = max(dp[j], dp[j-xi(i)]+xi(i)); } } if(dp[n] == n) cout << "YES\r\n"; else cout << "NO\r\n"; } return 0; }将每个数 xi 看成是体积为 xi! 的物品,而 dp[j] 数组的含义是容量为 j 大小的背包最多可以放入多大容积的物品。所以只要确认最后 dp[n] == n 即可判断n大小的背包是否可以刚刚好被装满,从而输出YES or NO
#include <iostream> using namespace std; int factorial(int n) { //求阶乘 return n <= 1 ? 1 : n * factorial(n - 1); } int main() { int n; while (cin >> n) { for (int i = 9; i >= 0; i--) { int factorial_i = factorial(i); if (n >= factorial_i) { n -= factorial_i; } } cout << (n == 0 ? "YES" : "NO") << endl; } return 0; }
// https://www.nowcoder.com/practice/42cb1c7f7344466b8cb1710cb12d06b1?tpId=62&tqId=29456&tPage=1&rp=1&ru=/ta/sju-kaoyan // 疏忽的点,0 的阶乘是 1 !!! #include<vector> #include<algorithm> #include<iostream> using namespace std; bool can_be_sum=false; int n; vector<int> factorials; // vector<int> visited; 一维单向,可以不需要这个数组标记 void dfs(int cur_sum, int idx){ if(cur_sum == n){ can_be_sum = true; return ; } else if(cur_sum > n) return ; if(idx==factorials.size()) return ; dfs(cur_sum+factorials[idx], idx+1); dfs(cur_sum, idx+1); return ; } int main(){ factorials.push_back(1); int fact=1; for(int i=1; fact<=1000001; ++i){ fact *= i; factorials.push_back(fact); } string ret; while(cin >> n){ can_be_sum = false; dfs(0, 0); ret = can_be_sum ? "YES" : "NO"; cout << ret << endl; } return 0; }
#include<iostream> #include<cstdio> using namespace std; const int maxn = 15; //判断输入的数是不是连续的阶乘之和和,(n≤1,000,000) int dp[maxn] = {0};//阶乘表 int f(int n) { if(n == 0 || n == 1) return 1; if(dp[n] != 0) return dp[n]; else return dp[n] = n * f(n - 1); } bool flag = false; //判断从i到j的阶乘和是否为n void DFS(int i, int j, int n) { //边界 while(dp[j]> n) --j; if(i > j || n < 0) return; if(n - dp[j] == 0) { flag = true; return; } DFS(i, j - 1, n - dp[j]); } int main () { f(10); //打印阶乘表 dp[0] = dp[1] = 1; int n; while(scanf("%d", &n) != EOF) { DFS(0, 10, n); if(flag) printf("YES"); else printf("NO"); } return 0; }
两个DP思路:
1、n是否可以表示。拆解为n-x是否可以表示,但会出现阶乘重复使用的问题。
2、每个数选或不选,即0-1背包问题。
提前计算出所有<=n的阶乘。问题转化为从一个有序数组中找出若干个,每个只能用一次,使其和等于一个特定数。每个数有选和不选两种状态,这就是经典的0-1背包问题。本题还可以做空间优化。
#include <cstdio> (802)#include <vector> using namespace std; int main(){ int n, temp=1, x=1; scanf("%d", &n); vector<int> fac; while(temp<=n){ fac.emplace_back(temp); temp *= x; x++; } int m = x-1; bool dp[n+1]={}; dp[0] = true; for(int k=1; k<=m; k++){ for(int t=n; t>=0; t--){ dp[t] = t>=fac[k-1] ? (dp[t] || dp[t-fac[k-1]]) : dp[t]; } } if(dp[n]) printf("YES"); else printf("NO"); return 0; }
//注意4也是可以的,因为0!+1!+2!=4,即不要忘了0的阶乘 #include<iostream> using namespace std; int result(int x){ if(x==0) return 1; else return x*result(x-1); } int main(){ int n,i,a[10],temp; for(i=0;i<=9;i++) a[i]=result(i); while(cin>>n){ int sum=n; int flag=1; for(i=0;i<=9;i++) if(a[i]>n){ temp=i; break; } for(i=temp-1;i>=0;i--){ if(sum-a[i]<0) continue; sum=sum-a[i]; if(sum==0){ cout<<"YES"<<endl; flag=0; break; } } if(flag==1) cout<<"NO"<<endl; } return 0; }
#include <iostream> #include <cstdio> using namespace std; const int maxn = 10; int f[maxn]; void init() { f[0] = 1; for(int i = 1; i < maxn; i++) { f[i] = f[i - 1] * i; } } int main() { init(); int n; while(scanf("%d", &n) != EOF) { for(int i = maxn - 1; i >= 0; i--) { if(n >= f[i]) n -= f[i]; } if(n == 0) printf("YES\n"); else printf("NO\n"); } return 0; }