E. Common Number (思维 + 规律)
Posted willems
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Common Number (思维 + 规律)相关的知识,希望对你有一定的参考价值。
题意: 有一个函数 f(x) 是这样定义的
然后我们定义路径 path(x),为令 x = f(x) 直到 x == 1;
例如: path(15)=[15,14,7,6,3,2,1], path(32)=[32,16,8,4,2,1].
现在给你 n 和 k。 问你在 1 ~ n 的所有数的路径中出现至少 k 次的最大的数是多少。
解: 考虑对于每个 x 在路径出现的次数:count(x);
若 x 为偶数,那么,路径中有 x 的数,有 x + 1, 2x, 2x+1, 2x+2, 2x+3, 4x, 4x+1, 4x+2,....4x+7;
若 x 为奇数,那么,路径中有 x 的数,有 2x, 2x + 1, 4x, 4x + 1, 4x + 2, 4x + 3, 8x,......
那么对于每个 x 的 count(x) 我们可以在 logn 时间里求得。
这里还有一个性质, count(x) >= count(x + 2);
显然, x 和 x + 2 的奇偶性是一样的,那么,对于同样的上限, 若存在路径中包含 x + 2 的数 a;
那么肯定存在一个更小的数 b ,路径中 包含 x;
然后,我们就可以二分求得了。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX using namespace std; const int mod = 1e9 + 7; bool check(LL x, LL k, LL n) { LL l = x, r = x + 1LL; if(x & 1) r--; LL res = 0LL; while(l <= n) { res = res + min(n, r) - l + 1; l = l << 1LL; r = (r << 1LL) + 1LL; } return res >= k; } int main() { LL n, k; scanf("%I64d %I64d", &n, &k); LL l = 1LL, r = n + 1LL, ans = 1LL; while(l <= r) { LL mid = (l + r) >> 1LL; if(check(mid << 1LL, k, n)) { l = mid + 1LL; ans = max(ans, mid << 1LL); } else if(check((mid << 1LL) - 1LL, k, n)) { l = mid + 1LL; ans = max(ans, (mid << 1LL) - 1LL); } else r = mid - 1LL; } printf("%I64d ", ans); return 0; }
以上是关于E. Common Number (思维 + 规律)的主要内容,如果未能解决你的问题,请参考以下文章