【题目】
BZOJ
一个数
A
A
A,如果它转成二进制后
B
B
B。
A
A
A是
B
B
B的后缀,这个数就是我们所要的。
现在给出数字
n
n
n,求第
n
n
n个这样的数。
n
≤
1
0
4
n \leq 10^4
n≤104
【解题思路】
观察发现,一个
1
0
k
10^k
10k的十进制数在二进制下末尾一定恰有
k
k
k个
0
0
0(因为
10
10
10的二进制末尾有
1
1
1个
0
0
0啊)
考虑从低位开始扩展,那么加入
1
0
k
10^k
10k以后对之前的数没有任何影响,之后的
+
1
+1
+1操作也不可能对以前的位有影响,那么合法的充要条件就是这一位的二进制原来是
0
0
0。
那么我们用
BFS
\text{BFS}
BFS进行扩展,保留前导
0
0
0,每次优先扩展一个
0
0
0即可。
显然每次最多扩展出一个不合法节点,处理一个节点的时间是
O
(
d
)
O(d)
O(d)的,其中
d
d
d是长度。
复杂度
O
(
n
d
)
O(nd)
O(nd),卡一卡应该就过了。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
const int N=10005,M=1005;
int n,cnt,len;
int num[N][M],pw[M];
queue<int>q,q0,q1;
void add(int *a,int *b,int *c)//a+b=c
{
for(int i=0;i<M-5;++i) c[i]=a[i]+b[i];
for(int i=0;i<M-5;++i) c[i+1]+=(c[i]>>1),c[i]&=1;
}
void mul10(int *a)
{
for(int i=M-6;~i;--i) if(a[i]) a[i]=0,++a[i+1],++a[i+3];
for(int i=0;i<M-5;++i) a[i+1]+=(a[i]>>1),a[i]&=1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ4404.in","r",stdin);
freopen("BZOJ4404.out","w",stdout);
#endif
scanf("%d",&n);--n;
if(!n){puts("1");return 0;}
num[++cnt][0]=0;num[++cnt][0]=1;pw[0]=1;
q.push(1);q.push(2);//wrong because forget push 2
while(1)
{
++len;mul10(pw);
//for(int i=0;i<M;++i) printf("%d",pw[i]);puts("");
while(!q.empty())
{
int x=q.front();q.pop();
if(num[x][len]==1) continue;
q0.push(x);--n;++cnt;
add(num[x],pw,num[cnt]);
if(!n)
{
for(int i=len;~i;--i) printf("%d",num[cnt][i]); puts("");
return 0;
}
q1.push(cnt);
}
while(!q0.empty()) q.push(q0.front()),q0.pop();
while(!q1.empty()) q.push(q1.front()),q1.pop();
}
return 0;
}