AcWing 3481. 阶乘的和

 

AcWing 3481. 阶乘的和

给定一个非负整数 nn,请你判断是否存在一些整数 xixi,能够使得 n=∑1≤i≤txi!n=∑1≤i≤txi!,其中 t≥1,xi≥0,xi=xj iff i=jt≥1,xi≥0,xi=xj iff i=j。

iffiff 表示当且仅当。

输入格式

输入包含多组测试数据。

每组数据占一行,包含一个非负整数 nn。

最后一行是一个负数,表示输入结束,无需处理。

输出格式

每组数据输出一行结果,如果 nn 能表示为若干数的阶乘之和,则输出 YES,否则输出 NO

数据范围

0≤n≤1060≤n≤106,
每组输入最多包含 100100 组数据。

输入样例:

9
-1

输出样例:

YES

这个题目值得说的是二进制枚举

我们就是利用了二进制的特性 ,我们就可以用0和1代表选和不选。

如果选出为1 2 3 4 5的位置,则如下表:

                                  1                        2                     3               4                5
二进制                       1                        0                     1               1                0
状态                          选                    不选                 选              选              不选
上面说有5个位置如果全选的话就是11111对应的十进制数就是31, 这个区间上每一个整数代表一个集合一共  32个集合,上表就是数字22(二进制:10110)所代表的集合:1 3 4。

所以我们遍历每一个集合:

for(int i = 0; i < (1 << n); i++)
设s = 13(二进制为1101)代表我们选0 2 3位置上的数值;

那么我们如何找到每个位置上的数值呢?

我们遍历的是二进制的十进制表示(比如13),我们当然可以转化为二进制再枚举每一位,但是,这很麻烦;

一个很巧妙的方式就是利用位运算。

1<<0=1(0);

1<<1=2(10);

1<<2=4(100);

1<<3=8(1000);

1<<4=16(10000);

...

1<<7=128(10000000);

...

看出来了吧!我们只需要将13&(1<<i)我们便可以得到每一位是不是1 (1<< i 除了那一位,剩余的都是0,所以我们就可以得到那一位是不是1)

-------------------------------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------

现在讲本题,2的10次方就超过了10^6了,所以枚举

1到10的和是不是存在,就用到了二进制枚举了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>

using namespace std;

int f[10];
set<int> S;

int main()
{
    for (int i = 0; i < 10; i ++ )
    {
        f[i] = 1;
        for (int j = i; j; j -- )
            f[i] *= j;
    }

    for (int i = 1; i < 1<<10; i ++ )
    {
        int s = 0;
        for (int j = 0; j < 10; j ++ )
            if (i&(1<<j))
                s += f[j];
        S.insert(s);
    }

    int n;
    while (cin >> n, n >= 0)
        if (S.count(n))
            puts("YES");
        else
            puts("NO");
    return 0;

}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值