【二进制枚举】【CF Div2 C】

2022.3.4  https://codeforces.com/contest/1646/problem/C

题意: 给一个数, 问可以最少有几个以下的数构成: 1.x! 2.2^x(x在每次都是任意数) t<=100, n<=10^13, 限时: 3秒 我当时的想法是: 2的某次方就看它的二进制哪里是1就行了, 如果n减去一个阶乘使它的1个数减少那么就减去这个阶乘。如果没有能使1减少的方案就加上n剩余的1的个数 误区: 有的阶乘减去后1的个数并没有减少, 但是再减去另一个阶乘却能去掉大于2个1, 而且也无法保证减去的数不一样 所以啊, 想错了

我去, 看了官方题解,用二进制枚举, 一共就最多1! ~ 15!, 用二进制来枚举, 我去我怎么没想到啊啊啊

 

哦对了, 还学到一个新东西, 头文件 #include <cstdio> , 函数 __builtin_popcount (unsigned u), 功能 返回u的二进制有多少个1

 

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e5+10;
const LL MAXX = 1e12;//注意const后面是long long
LL jch[100];
int idx;

int bist_num(LL nn)
{
int res =0;
while(nn)
{
if(nn&1)res ++;
nn>>=1;
}
return res;
}

void init()
{
jch[1] = 1;
for(int i = 2; jch[i-1]<=MAXX; i++) jch[i] = jch[i-1]*(LL)i, idx=i+1;
}

int main()
{
init();
int t;
cin >> t;

while(t --)
{
LL n, res = 99;
cin >> n;
for(LL i = 0; i < (1<<idx); i ++)
{
LL now = 0, cout = 0;
for(int j = 0; j < idx; j ++)
if(i>>j&1)
now+=jch[j], cout ++;

if(now<=n)res = min(res, cout + bist_num(n-now));
}
cout <<res <<endl;
}
return 0;
}

 

posted @ 2022-03-07 19:22  la-la-wanf  阅读(39)  评论(0编辑  收藏  举报