HDU - 5637 Transform (思维、bfs预处理)

HDU - 5637

HDU - 5637 Transform (思维、bfs预处理)_第1张图片
题目大意:

给出n个数的序列a,对于一个整数x,有两种操作:
1.改变x二进制中任一位
2.将x变为x^a[i]
m次查询,每次查询输入两个整数x和y,问x最少经过多少次操作可以变成y

求最少多少次操作可以值得x变成y实际上不就是一个“迷宫求最短路”嘛。
这里是状态转移到另一个状态的最短路,也就是直接bfs即可。易得最先转移到的就是最短路。

数据比较大m有1e5,每次输入数据再爆搜肯定要超时。
因为这里都只涉及到异或操作。

我们发现s^(t[1]^t[2]^...t[j])=t。因为A^B=C => A^C=B那么转化成(t[1]^t[2]^...t[j])=s^t,也就是说我们只需要找到如何使用最少的操作从0开始得到s^t即可。

这样我们就可以直接先预处理出整个数的最小距离,然后输入查询O(1)按照题目要求输出即可。

代码就是一个简单的bfs主要是思路,一般这类的经过最少操作次数构造或者使得一个数变成另一个数大体上都是这个思路。

一般看不出什么算法的题都可以用爆搜解决。

#include
#include
#include
#include

using namespace std;
typedef long long ll;
const int N = 5000007, mod = 1e9+7;

int n, m, t;
int a[N];
int dist[N];

void bfs(){
    memset(dist, -1, sizeof dist);
    queue<int>q;
    dist[0] = 0;
    q.push(0);
    while(q.size()){
        int x = q.front();
        q.pop();

        for(int i = 1;i <= n ; ++ i)
            if(dist[x ^ a[i]] == -1){
                dist[x ^ a[i]] = dist[x] + 1;
                q.push(x ^ a[i]);
            }
        for(int i = 0;i <= 17 ; ++ i){
            if(dist[x ^ (1 << i)] == -1){
                dist[x ^ (1 << i)] = dist[x] + 1;
                q.push(x ^ (1 << i));
            }
        }
    }
}

int main(){
    scanf("%d", &t);
    while(t -- ){
        scanf("%d%d", &n, &m);
        for(int i = 1;i <= n; ++ i)
            scanf("%d", &a[i]);
        bfs();

        ll ans = 0;
        for(int i = 1;i <= m ; ++ i){
            int a, b;
            scanf("%d%d", &a, &b);
            ans = (ans + (1ll * i * dist[a ^ b]) % mod) %mod;
        }
        printf("%lld\n", ans);
    }

    return 0;
}

你可能感兴趣的:(HDU,#,BFS,【死亡思维题】)