CF1734F (分治,记搜)
esquigybcu · · 题解
很奇怪的一种做法,但是过了。好像跟 editorial 的递归做法差不多。
题意
定义
- 一开始
S=\texttt{0} - 然后把
S 按位取反之后拼接在S 后面 - 把 2 重复无限多次
然后
做法
首先注意到
证明:对
i 归纳。设i 的二进制中最高的一位是2^k ,那么2^k\le n<2^{k+1} ,由构造有S_i 与S_{i-2^k} 相反。\square
那么问题就变成了对多少个
若
时间/空间复杂度
根据上面的讨论我们知道每次
引理:有正整数
n ,每次可以把她变成\lfloor n/2\rfloor 或者\lfloor (n+1)/2\rfloor ,至多可以达到O(\log n) 个数。
这里感谢 I_am_Accepted 大佬的证明。
证明:不难对
k 归纳证明,操作k 次可以达到的数是两个相邻的数。而操作次数至多O(\log n) ,即证。
从而每次至多达到
代码
注意 unordered_map 要防 hack。代码中的 dfs(n, m, i) 表示有多少个
// Let QwQ bless me. I love QwQ forever!
#include <stdio.h>
#include <stdint.h>
#include <utility>
#include <unordered_map>
#include <chrono>
#include <random>
#pragma GCC optimize("-Ofast")
#pragma GCC target("avx2")
using i32 = int32_t;
using i64 = int64_t;
using u32 = uint32_t;
using u64 = uint64_t;
struct hesh
{
inline size_t operator()(std::pair<u64, u64> p) const
{
static const u64 r = std::chrono::high_resolution_clock().now().time_since_epoch().count();
u64 x = p.first + p.second * r;
x ^= r;
x ^= (x >> 29);
x *= 9;
return x;
}
};
std::unordered_map<std::pair<u64, u64>, u64, hesh> umap;
u64 solve(u64 n, u64 m, u64 i)
{
if (i == 1) return m - solve(n, m, 0);
if (m == 0) return 0;
if (m == 1) return __builtin_parity(n) != 0;
if (umap.count({n, m})) return umap[{n, m}];
u64 ans = solve(n / 2, (m + 1) / 2, n % 2) + solve((n + 1) / 2, m / 2, n % 2);
umap[{n, m}] = ans;
return ans;
}
int main()
{
int q; scanf("%d", &q);
while (q--)
{
u64 n, m; scanf("%lld %lld", &n, &m);
printf("%lld\n", solve(n, m, 0));
}
}