cf1646c Factorials and Powers of Two(状态暴力枚举)

传送门

题意

给定一个数,问是否能将成拆分为不同的阶乘及 2 2 2 的幂次方之和,且最少需要几个这样的数字。

根据二进制的特点,容易得到本题一定有解,且所需数字最多的方案即为二进制中 1 1 1 的个数。因此简化答案需要用阶乘替换若干个 2 2 2 的幂次方。

由于本题的数据范围为 1 0 12 10^{12} 1012 ,因此能取到的最高阶乘为 14 14 14 ,可以对是否取某个阶乘的状态进行枚举,并用 _ _ b u i l t i n _ p o p c o u n t ( ) \_\_builtin\_popcount() __builtin_popcount() 函数求得去除该所选阶乘后剩下的二进制中 1 1 1 的个数。则该状态的答案即为最后 1 1 1 的个数 + 所选阶乘的数量。

大坑点:该函数最大可接受的传入为 i n t int int,调试 2 2 2 的幂次方时发现传入 4294967296 4294967296 4294967296 就寄了,因此要使用 _ _ b u i l t i n _ p o p c o u n t l l ( ) \_\_builtin\_popcountll() __builtin_popcountll() 处理。

#include <bits/stdc++.h>
#define int long long
const int N=1e5+10;
using namespace std;

int p[15];

void deal(){
	p[1]=p[0]=1;
	for(int i=2;i<=14;i++)
		p[i]=i*p[i-1];
}

void solve(){
	int n;
	cin>>n;
	int ans=N;
	
	for(int state=0;state<(1<<14);state++){
		int cnt=0,now=n;
		for(int i=0;i<14;i++){//对于每个数的阶乘 
			if((state>>(i))&1){//如果state该位为1 说明选择 
				if(now<p[i+1]){//当前数小于该阶乘 没有意义 
					continue;
				}
				else{
					cnt++;
					now-=p[i+1];
				}
			}
		}
		int sum=__builtin_popcountll(now);
		sum+=cnt;//选择了几次阶乘 
		ans=min(ans,sum);
	}
	cout<<ans<<endl;
}

signed main(){
	int t;
	deal();
	cin>>t;
	while(t--)
		solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值