我被开区间坑了啊!! 其实闭区间也不错 闭区间是INI_MAX 加个1变成开区间溢出了 坑死个人了= =
主要思路
首先要确定目标有多少个1 就把1的个数为0 1 2 的加起来 什么时候超过k了 就停止 这样就确定了1的个数
然后需要在这些数里找到目标 方法是二分 然后就没有然后了
负数先忽略最高位的1 然后搞完再把符号弄回来就行了
还有就是边界值为0的时候需要有一些特殊讨论 总之到处是坑啊
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned int uint;
const int MAXN = 32;
int d[MAXN+10][MAXN+10], bit[MAXN+10];
void init()
{
for(int i = 0; i <= MAXN; i++) d[i][0] = 1;
for(int i = 1; i <= MAXN; i++)
for(int j = 1; j <= i; j++)
d[i][j] = d[i-1][j] + d[i-1][j-1];
}
LL cal(int x, int k)
{
int Len = 0; LL ans = 0;
memset(bit, 0, sizeof(bit));
while(x) {
bit[++Len] = x & 1;
x >>= 1;
}
for(int i = Len; i >= 1; i--)
if(bit[i])
{
if(k < 0) break;
ans += d[i-1][k];
k--;
}
if(!k) ans++;
return ans;
}
bool check(int L, int R, int k, int rank)
{
int tmp = cal(R, k) - cal(L-1, k);
return tmp >= rank;
}
int solve(int L, int R, int x)
{
int i, st = L;
for(i = 1; i <= MAXN; i++)
{
LL tmp = cal(R, i) - cal(L-1, i);
if(tmp < x) x -= tmp;
else break;
}
while(L < R)
{
int mid = ((LL)L + R) >> 1;
if(check(st, mid, i, x))
R = mid;
else
L = mid+1;
}
return L;
}
int main()
{
init();
int T; scanf("%d", &T); while(T--) {
int L, R, K;
scanf("%d%d%d", &L, &R, &K);
if(R > 0) {
if(L == 0 && K == 1) { printf("0\n"); continue; }
if(L == 0) L++, K--;
int ans = solve(L, R, K);
printf("%d\n", ans);
}
else {
if(R == 0 && K == 1) { printf("0\n"); continue; }
if(R == 0) R--, K--;
int flag = R < 0;
L = (uint)L & (((uint)1 << 31) - 1);
R = (uint)R & (((uint)1 << 31) - 1);
if(R == 0) {
if(K == 1) { printf("%d\n", ((uint)1 << 31)); continue; }
R++; K--;
}
int ans = solve(L, R, K);
printf("%d\n", flag * ((uint)1 << 31) + ans);
}
}
}