[UVALive3675]Sorted bit sequence && 数位DP

我被开区间坑了啊!! 其实闭区间也不错 闭区间是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);
		}
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值