牛客小白月赛79 D

题意:

给定数 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 

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;
}

你可能感兴趣的:(图论,#,最短路,算法)