题解:SP1182 SORTBIT - Sorted bit squence
题意
将区间
的所有整数按照其二进制位表示的数中 的数量从小到大排序。如果 的数量相同,则按照数的大小排序。求序列中第 个数。 其中,负数使用补码来表示:一个负数的二进制数与其相反数的二进制数之和恰好等于
。
分析
考虑用 uint32_t
存储负数,这样得到的就是二进制数就是符合题目描述的补码。
根据条件 uint32_t
后在值域上是连续的。(除了
先讨论第一个排序条件:按照其二进制位表示的数中
考虑实现这样一种操作:查询区间
显然在左端点固定的情况下随着右端点增加操作的结果是单调不降的。
从
这一部分说的有点抽象,建议结合代码理解。
得到了第
查找第一个
在 int
下输出这个数即可。
现在我们只需要实现这个操作。
发现这个操作比较典型,使用数位 dp 解决。
时间复杂度
code
#include<bits/stdc++.h> using namespace std; int dp[40][40][2]; typedef bitset<32> uint_t; uint32_t dfs(int pos, int cnt, int num, const uint_t &upr, bool up, int tcnt) { if(pos==-1) return cnt==tcnt; if(cnt>tcnt) return 0; if(!up&&dp[pos][tcnt-cnt][num]!=-1) return dp[pos][tcnt-cnt][num]; uint32_t ret=0; int mx=up?upr[pos]:1; for(int i=0;i<=mx;i++) ret+=dfs(pos-1, cnt+i, i, upr, up&&i==upr[pos], tcnt); if(!up) dp[pos][tcnt-cnt][num]=ret; return ret; } uint32_t count_bit(uint32_t l, uint32_t r, int k) { uint_t bl=l-1, br=r; if(!l) return dfs(31, 0, 0, br, 1, k); return dfs(31, 0, 0, br, 1, k)-dfs(31, 0, 0, bl, 1, k); } void solve() { int64_t l, r, k; cin>>l>>r>>k; if((!l||!r)&&k==1) return cout<<0, void(); uint32_t L=l, R=r; if(l<0&&!R) R=UINT32_MAX, k--; if(r>0&&!L) L++, k--; int s=1; for(;;s++) { uint32_t v=count_bit(L, R, s); if(v>=k) break; k-=v; } l=L-1, r=R; while(l+1<r) { uint32_t mid=(l+r)>>1; if(count_bit(L, mid, s)<k) l=mid; else r=mid; } cout<<(int)r<<'\n'; } int main() { memset(dp, -1, sizeof dp); int t; cin>>t; while(t--) solve(); }
本文作者:Jimmy-LEEE
本文链接:https://www.cnblogs.com/redacted-area/p/18379562
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步