题目链接:http://codeforces.com/problemset/problem/590/A
题目大意是给两种操作,然后给你一个s,一个t,求s至少需要多少次操作到t。
考虑到第一种操作是将某一位取反,而第二种操作是抑或一个数。
显然第一种操作也是可以通过抑或一个数得到的。比如:第i位取反,相当于抑或(1<<i)这个数。于是就将n个数扩大到n+17就可以了,因为100000最多17位。
此外如果p^a^b^c...=q的话,那么a^b^c...=p^q。于是,只需要求出p^q至少需要几个数抑或而成就可以了。
然后跑一个类似于最短路就可以了,此处采用spfa。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <string> #define LL long long #define MOD 1000000007 using namespace std; int n, m, a[50]; int dis[200005]; bool vis[200005]; void input() { scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) scanf("%d", &a[i]); for (int i = 0; i < 17; ++i) a[i+n] = 1<<i; n += 17; //spfa memset(dis, -1, sizeof(dis)); dis[0] = 0; memset(vis, false, sizeof(vis)); vis[0] = true; queue<int> q; q.push(0); int k, v, t; while (!q.empty()) { k = q.front(); q.pop(); vis[k] = false; for (int i = 0; i < n; ++i) { v = k^a[i]; if (dis[v] != -1 && dis[v] <= dis[k]+1) continue; dis[v] = dis[k]+1; if (!vis[v]) { q.push(v); vis[v] = true; } } } } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for (int times = 1; times <= T; ++times) { input(); int s, t; LL ans = 0; for (int i = 1; i <= m; ++i) { scanf("%d%d", &s, &t); ans += (LL)i*dis[s^t]; ans %= MOD; } cout << ans << endl; } return 0; }
时间: 2024-10-11 16:55:22