首页 > 试题广场 >

Sum of Factorials

[编程题]Sum of Factorials
  • 热度指数:5415 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
    John von Neumann, b. Dec. 28, 1903, d. Feb. 8, 1957, was a Hungarian-American mathematician who made important contributions to the foundations of mathematics, logic, quantum physics, meteorology, science, computers, and game theory. He was noted for a phenomenal memory and the speed with which he absorbed ideas and solved problems. In 1925 he received a B.S. diploma in chemical engineering from Zurich Institute and in 1926 a Ph.D. in mathematics from the University of Budapest, His Ph.D. dissertation on set theory was an important contributions to the subject.     At the age of 20, von Neumann proposed a new definition of ordinal numbers that was universally adopted. While still in his twenties, he made many contributions in both pure and applied mathematics that established him as a mathematician of unusual depth. His Mathematical Foundation of Quantum Mechanics (1932) built a solid framework for the new scientific discipline.     During this time he also proved the mini-max theorem of GAME THEORY. He gradually expanded his work in game theory, and with coauthor Oskar Morgenstern he wrote Theory of Games and Economic Behavior (1944).     There are some numbers which can be expressed by the sum of factorials. For example 9, 9 = 1! + 2! + 3! . Dr. von Neumann was very interested in such numbers. So, he gives you a number n, and wants you to tell whether or not the number can be expressed by the sum of some factorials. Well, it is just a piece of case. For a given n, you will check if there are some xi, and let n equal to Σt (上标) i=1(下标) xi! (t≥1, xi≥0, xi = xj <==> i = j)            t      即 Σ  xi! (t≥1, xi≥0, xi = xj <==> i = j)           i=1     If the answer is yes, say "YES"; otherwise, print out "NO".

输入描述:
    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.
示例1

输入

9
2

输出

YES
YES
错了两次,但其实还蛮简单的,不过考虑到0的阶乘是1,真的神奇
#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;
    }
}

发表于 2019-02-10 11:56:20 回复(0)
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
编辑于 2018-10-14 13:05:18 回复(0)
#include<iostream>
using namespace std;
int main()
{
    int n;
    int fac[10]={1};
    for(int i=1;i<10;fac[i++]=fac[i-1]*i);
    while(cin>>n)
    {
        for(int i=9;i>=0;n<fac[i] ? i--:n-=fac[i--]);
        n==0 ? cout<<"YES"<<endl:cout<<"NO"<<endl;
    }
}
发表于 2018-08-30 16:54:54 回复(1)
#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");
    }
}

发表于 2020-04-19 14:29:24 回复(0)
【打表】
题意:判断输入的数是不是连续的阶乘之和。
注意题目要求n<=10^6,所以打表只要记录0-10的阶乘即可。(0!=1)
#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;
}


发表于 2020-04-17 12:39:11 回复(3)

能减就减,因为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;
}
发表于 2019-03-27 20:11:34 回复(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中的一个数表示。

发表于 2018-02-27 14:28:59 回复(0)
//用递归写的
#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;
    }
        
}

发表于 2017-07-12 21:39:43 回复(0)

#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;

}


发表于 2018-03-02 21:17:13 回复(1)
给出两个与阶乘无关的通用解法,DFS与DP
#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;
}

发表于 2020-02-29 15:12:25 回复(0)
7为什么预期输出是YES?题意不是要求连续的阶乘和吗?
发表于 2021-02-02 16:58:16 回复(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;
    }
}

发表于 2024-01-17 12:44:40 回复(0)
可以转为01背包从而用动规的思想来解决这道题:
#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

编辑于 2024-03-17 15:41:39 回复(0)
#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;
}

编辑于 2024-03-02 11:49:40 回复(0)
疏忽的点,没有注意到 0 的阶乘是 1,
另外,没有理解到题目中需要的是连续的阶乘,所以用了 dfs 判断数字是否可以表示成多个不同自然数阶乘的和。

// 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;
}


发表于 2023-03-20 17:42:25 回复(0)
#include "stdio.h"

int main(){
    int factor[20];int sum = 1;
    for (int i = 0; i < 12; ++i) {
        if(i == 0)
            factor[i] = 1;
        else{
            sum *= i;
            factor[i] = sum;
        }
    }
    int n;
    while (scanf("%d",&n)!=EOF){
        int pos = 11;
        while (pos >= 0){
            if(factor[pos] <= n){
                n = n - factor[pos];
            }
            if(n == 0)
                break;
            pos--;
        }
        if(pos < 0){
            printf("NO\n");
        } else{
            printf("YES\n");
        }
    }
}

发表于 2023-03-14 09:49:09 回复(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;
} 


发表于 2021-02-04 18:25:51 回复(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;
}
发表于 2020-04-01 15:42:01 回复(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;
}

发表于 2020-03-26 19:45:17 回复(0)
能减就减,因为n!一定大于1!+ 2 ! + ... + (n - 1)!
#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;
}


编辑于 2020-03-21 22:14:52 回复(1)

问题信息

难度:
29条回答 4789浏览

热门推荐

通过挑战的用户

查看代码