总体难度递增。感觉 E 题的做法比较新奇。F 题在 51nod 有强化版本。
E 牛妹游历城市
题意:给定 n n n 个点,第 i i i 个点有权值 a i a_i ai。如果对于 i , j i, j i,j 有 a i and a j a_i \operatorname{and} a_j aiandaj 不为 0 0 0,那么 i , j i, j i,j 间有无向边,边权为 lowbit ( a i and a j ) \operatorname{lowbit}(a_i \operatorname{and} a_j) lowbit(aiandaj)。问从 1 1 1 到 n n n 的最短路。
我们可以依次考虑每一个位,然后把点权有相同位的点互相连一条边。但这样边的数目可能是 O ( n 2 ) O(n^2) O(n2)。
更好的做法是对当前位建立一个虚拟点,设为 u u u。遍历所有点,如果 i i i 的点权满足这一位上为 1 1 1,那么连一条从 i i i 到 u u u 的边,边权为这一位对应的二进制数;再连一条从 u u u 到 i i i 的边,边权为 0 0 0。这样边数就下降到了至多 64 n 64n 64n。跑 Dijkstra 可以通过。
本题题解区还有些更高妙的做法。
#include <bits/stdc++.h>
#define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp)
#define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp)
using namespace std;
typedef long long ll;
int read(){
int f = 1, x = 0;
char c = getchar();
while (c < '0' || c > '9'){
if(c == '-') f = -f; c = getchar();}
while (c >= '0' && c <= '9')x = x * 10 + c - '0'