【暴力】Factorials and Powers of Two—CF1646C

1 篇文章 0 订阅
1 篇文章 0 订阅

Factorials and Powers of Two—CF1646C

思路

实在没想到这个题居然是暴力。

我们先不考虑选择的阶乘数字和指数幂数字中有重复的情况。因为 1 ≤ n ≤ 1 0 12 1\le n\le 10^{12} 1n1012,并且 15 !   >   1 0 12 15!~>~10^{12} 15! > 1012,所以我们可以暴力枚举这 14 14 14 个阶乘数是否选择。

对于每一种阶乘数的选择情况,计算 n n n 还有多少需要用指数幂数字“填充”,我们记这个大小作 l e a v e leave leave

需要用的指数幂数字的个数为 l e a v e leave leave 的二进制中数字 1 1 1 的个数。这里利用二进制非常巧妙,我没有想到QWQ。

现在我们回到刚开始的那个问题:如果最优选择的方案中选择了数字 x x x,并且在阶乘数字和指数幂数字中都选择了 x x x,那么这种最优解就是不符合题意的。

这里需要证明一个性质:最优解中一定不会在阶乘数字和指数幂数字中都选择一个相同的数字。
证明:
我们假设同时选择了数字 x x x,那么我们完全可以把这两次选择变成一次选择,即选择一个指数幂数字 2   ∗   x 2~*~x 2  x。如果 2   ∗   x 2~*~x 2  x 之前已经选择了,我们也可以合并这两个 2   ∗   x 2~*~x 2  x 为一个 4   ∗   x 4~*~x 4  x。很容易看出来这个过程不会无限循环下去。

C o d e Code Code

#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;

int n;
int a[20], la;
int res;

int dfs(int start, int leave, int num) {
	if (num >= res) { // 最优化剪枝
		return num;
	}
	if (start == la + 1) {
		while (leave) {
			if (leave & 1) {
				num ++;
			}
			leave >>= 1;
		}
		res = min(res, num);
		return num;
	}
	res = min(res, dfs(start + 1, leave, num));
	if (leave >= a[start]) {
		res = min(res, dfs(start + 1, leave - a[start], num + 1));
	}
	return res;
}

void solve() {
	cin >> n;
	
	la = 0;
	int base = 1;
	for (int i = 1; i * base <= n; i ++) {
		base *= i;
		a[++ la] = base;
	}
	
	res = 1e18;
	dfs(1, n, 0); // 暴力枚举选择的阶乘数字都有哪些
	cout << "      ";
	cout << res << "\n";
}

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T = 1;
	cin >> T; cin.get();
	while (T --) solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值