https://pintia.cn/problem-sets/1571150153619189760/problems/1571150314621562883
题意
定义
c
t
z
(
x
)
ctz(x)
ctz(x) 为
x
x
x 的二进制表示后缀
0
0
0 的个数;
p
o
p
c
o
u
n
t
(
x
)
popcount(x)
popcount(x) 为
x
x
x 的二进制表示中
1
1
1 的个数。
如果
c
t
z
(
x
)
=
p
o
p
c
o
u
n
t
(
x
)
ctz(x)=popcount(x)
ctz(x)=popcount(x),则称
x
x
x 为一个好数。
一共 T 次询问,每次询问给出一个区间 [ l , r ] [l, r] [l,r],找到区间中的任意一个好数。不存在输出 -1。
1 ≤ T ≤ 1 0 5 , 1 ≤ l ≤ r ≤ 1 0 9 1≤T≤10^5, 1≤l≤r≤10^9 1≤T≤105,1≤l≤r≤109
思路
一共 1e9 个数,但是满足描述中严格限制的只有 5e5 个数。
一共30位,暴搜+剪枝完全可以求出所有满足的数。所有数预处理出来。
后面对于每个询问,找到第一个大于等于左端点的满足的数,判断是否在区间中。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long
const int N = 2000010, mod = 1e9+7;
int T, n, m;
int a[N], sum;
int ans[N], idx;
vector<int> v;
void dfs(int u)
{
if(u > 30)
{
if(sum) return;
int x, res = 0;
for(int i=1;i<=30;i++)
{
if(i == 1) x = 1;
else x *= 2;
if(a[i]) res += x;
}
v.push_back(res);
return;
}
if(sum)
{
sum --;
a[u] = 1;
dfs(u+1);
sum ++;
}
a[u] = 0;
dfs(u+1);
}
signed main(){
for(int i=1;i<=16;i++)
{
for(int j=1;j<=i;j++) a[j] = 0;
a[i + 1] = 1;
sum = i - 1;
dfs(i+2);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
cin >> m;
while(m--)
{
int l, r; cin >> l >> r;
auto it = lower_bound(v.begin(), v.end(), l);
if(it == v.end()) cout << -1;
else
{
int x = *it;
if(x > r) cout << -1;
else cout << x;
}
if(m) cout << "\n";
}
return 0;
}
经验
多用点野路子,不是它说啥就是啥。不要光跟着它的思路走。
能 a 掉题目的方法都是好方法。