题意:
给定数 x ,每次可以选择将 x 变为 x*2 ,或是将 x 变为 x+1,求 x 变为 2 20 2^{20} 220倍数的最小代价。
思路:
因为对于 2 20 2^{20} 220次方倍数的点无意义,所以总共的点数只用 2 20 2^{20} 220即可。那么对于 x 的两种变换方式,我们可以把其抽象为 x 和 x*2 间连了一条边,x 和 x+1之间连了一条边。然后去bfs跑最短路即可。
但因为是多组询问,我们可以预处理上述的最短路信息,然后之间询问即可。
所以我们把终点当作起点,然后反向建边即可。
#include <bits/stdc++.h>using namespace std;
const int N = 2e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;
// #define endl "\n"
vector<int> e[N];void add(int u,int v)
{e[u].push_back(v);
}
int d[N];
void init()
{int res=1;for(int i=1;i<=20;i++) res*=2;for(int i=0;i<res;i++){add((i+1)%res,i);add((i*2)%res,i);}queue<int> q;q.push(0);memset(d,0x3f,sizeof d);d[0]=0;while(!q.empty()){auto t=q.front();q.pop();for(auto x: e[t]){if(d[x]>d[t]+1){d[x]=d[t]+1;q.push(x);}}}
}
void solve()
{ int n;cin>>n;n%=(1ll<<20);cout<<d[n]<<endl;}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;t=1;cin>>t;init();while(t--){solve();}system("pause");return 0;
}