C. Factorials and Powers of Two

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

题意:给定一个数k,问k能否通过若干个不同的数组成,并且这些数必须是阶乘或者2的幂次。

思路:考虑所有的阶乘,有选或者不选两种组合方式,阶乘选完后,再去看剩下的数中需要选几个2的幂次,取最小的组合方式作为题解即可。

总结:从二进制的角度考虑, 如果限制数字只是2的幂次,那题解就是k的有效bit位数。现在加了一个阶乘的限制,可以考虑暴力选择所有的阶乘组合,然后再去考虑有效的bit位数。一开始想的是全暴力,但是阶乘+幂次有50多个数,复杂度太高了,然后换成了双向dfs,复杂度降了一半,但还是TLE。。

vector<long long> nums;
constexpr long long N = (long long)1e12;
long long S = 0;
inline void preProcess() {
    long long fac = 1ll;
    for (long long i = 1; fac * i <= N; ++i) {
        nums.push_back(fac * i);
        fac *= i;
        S += nums.back();
    }
}



inline void solve() {
    long long k;
    cin >> k;

    int ans = -1;
    auto dfs = [&](auto&& self, int index, int p, int used, long long sum) ->void{
        if (sum > k) {
            return;
        }
        if (index == p) {
            long long v = k - sum;
            int cnt = ppcll(v);
            ans = ans == -1 ? used + cnt : min(ans, used + cnt);
            return;
        }

        self(self, index + 1, p, used + 1, sum + nums[index]);
        self(self, index + 1, p, used, sum);
    };

    dfs(dfs, 0, (int)nums.size(), 0, 0ll);

    cout << ans << '\n';
}

放个TLE代码

vector<long long> nums;
constexpr long long N = (long long)1e12;
long long S = 0;
inline void preProcess() {
	long long fac = 1ll;
	for (long long i = 1; fac * i <= N; ++i) {
		nums.push_back(fac * i);
		fac *= i;
		S += nums.back();
	}
	for (int i = 1; i < 63; ++i) {
		if ((1ll << i) > N) {
			break;
		}
		nums.push_back(1ll << i);
		S += nums.back();
	}

	sort(nums.begin(), nums.end());
}



inline void solve() {
	long long k;
	cin >> k;

	int ans = -1;

	int m = nums.size() / 2;

	map<long long, int> left, right;
	left[0] = right[0] = 0;
	auto dfs = [&](auto&& self, size_t curIndex, int index, long long sum, long long rem, int cnt, map<long long, int>& mapp) ->void {
		if (sum > k || sum + rem < k) {
			return;
		}
		if (mapp.count(sum)) {
			mapp[sum] = min(mapp[sum], cnt);
		}
		else {
			mapp[sum] = cnt;
		}
		if (curIndex > index) {
			return;
		}
		self(self, curIndex + 1, index, sum + nums[curIndex], rem - nums[curIndex], cnt + 1, mapp);
		self(self, curIndex + 1, index, sum, rem - nums[curIndex], cnt, mapp);
	};

	dfs(dfs, 0, m, 0ll, S, 0, left);
	dfs(dfs, m + 1, nums.size() - 1, 0ll, S, 0, right);
	for (auto[x, y] : left) {
		long long need = k - x;
		if (right.count(need)) {
			ans = ans == -1 ? y + right[need] : min(ans, y + right[need]);
		}
	}

	cout << ans << '\n';

}
posted @ 2025-06-24 09:26  _Yxc  阅读(13)  评论(0)    收藏  举报