CF1661B Getting Zero
题意
对于一个整数 ,可以进行如下操作之一改变 的值无限次:
- 。
- 。
记 为整数 被改变至 的最小次数,给出一个 个数的数列 ,求出所有的 。
分析
先把所有的 预处理出来,再处理询问。
显然将 改为 的最小次数就是将 改为 的最小次数,所以操作是可以反着来的,又有 ,因此我们把每个数 想象成顶点,根据操作来连边,我们可以通过求反图的最短路来求出所有的 ,一个 就可以实现。
那么应该如何连反边呢,假设我们已经求出了 ,那么在原图上它可以由以下三个数得到:
- 。
- 。
- 。
因此在 中判断这些数是否被更新了,如果没被更新过就更新并加入队列。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=4e4+10;
int n,m=32768,a[N],d[N];
queue<int>q;
int main(){
for(int i=1;i<m;i++)
d[i]=-1;
d[0]=0;
q.push(0);
while(q.size()){
int x=q.front();
q.pop();
if(d[(x-1+m)%m]==-1){
d[(x-1+m)%m]=d[x]+1;
q.push((x-1+m)%m);
}
if(x%2==0&&d[x/2]==-1){
d[x/2]=d[x]+1;
q.push(x/2);
}
if(x%2==0&&d[(x+m)/2]==-1){
d[(x+m)/2]=d[x]+1;
q.push((x+m)/2);
}
}
n=read();
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cout<<d[a[i]]<<" ";
return 0;
}

浙公网安备 33010602011771号