HDU 5637 Transform 单源最短路
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5637
题意:
http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=675&pid=1003
题解:
令n=(1<<17)-1。
首先很容易想到建图,跑最短路,不过有多次查询,如果每次都跑最短路的话要m*n*logn,会t。
所以可能是我们模型建的太一般化了,需要考虑题目的特殊性。
s到t的最少变化次数本质上等于0到s^t的最少变化次数。
所以我们只要求一次单源最短路径就可以了,只要nlogn的复杂度。
#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<queue> using namespace std; const int maxn = 1 << 17; const int mod = 1e9 + 7; const int INF = 1e9; typedef long long LL; vector<int> G[maxn]; int arr[22]; int n, m; int inq[maxn], d[maxn]; void spfa() { queue<int> Q; memset(inq, 0, sizeof(inq)); memset(d, 0x7f, sizeof(d)); d[0] = 0, inq[0] = 1, Q.push(0); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (d[v] > d[u] + 1) { d[v] = d[u] + 1; if (!inq[v]) { inq[v] = 1; Q.push(v); } } } } } void init() { for (int i = 0; i < maxn; i++) G[i].clear(); } int main() { int tc; scanf("%d", &tc); while (tc--) { scanf("%d%d", &n, &m); init(); for (int i = 0; i < n; i++) scanf("%d", arr + i); for (int i = 0; i < maxn; i++) { for (int j = 0; j < n; j++) { G[i].push_back(i^arr[j]); } for (int j = 0; j < 17; j++) { G[i].push_back(i ^ (1 << j)); } } spfa(); LL ans = 0; for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); ans += (LL)i*d[u^v]; ans%=mod; } printf("%lld\n", ans); } return 0; }