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';
}

浙公网安备 33010602011771号