HDU 5637:Transform

本文探讨了通过位操作及异或运算解决特定算法问题的方法,包括如何利用这些操作进行状态转换,以及如何通过广度优先搜索求解最小操作步数。

Transform

 
 Accepts: 47
 
 Submissions: 187
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
给出nn个整数, 对于一个整数xx, 你可以做如下的操作若干次:

  + 令xx的二进制表示为\overline{b_{31}b_{30}...b_0}b31b30...b0, 你可以翻转其中一个位.
  + 令yy是给出的其中一个整数, 你可以把xx变为x \oplus yxy, 其中\oplus表示位运算里面的异或操作.

现在有若干整数对(S, T)(S,T), 对于每对整数你需要找出从SS变成TT的最小操作次数.
输入描述
输入包含多组数据. 第一行有一个整数TT (T \le 20)(T20), 表示测试数据组数. 对于每组数据:

第一行包含两个整数nnmm (1 \le n \le 15, 1 \le m \le 10^5)(1n15,1m105), 表示给出整数的数目和询问的数目. 接下来一行包含nn个用空格分隔的整数a_1, a_2, ..., a_na1,a2,...,an (1 \le a_i \le 10^5)(1ai105).

接下来mm行, 每行包含两个整数s_isit_iti (1 \le s_i, t_i \le 10^5)(1si,ti105), 代表一组询问.
输出描述
对于每组数据, 输出一个整数S=(\displaystyle\sum_{i=1}^{m} i \cdot z_i) \text{ mod } (10^9 + 7)S=(i=1mizi) mod (109+7), 其中z_izi是第ii次询问的答案.
输入样例
1
3 3
1 2 3
3 4
1 2
3 9
输出样例
10
Hint
3 \to 434 (2次操作): 3 \to 7 \to 4374

1 \to 212 (1次操作): 1 \oplus 3 = 213=2

3 \to 939 (2次操作): 3 \to 1 \to 9319

注意到x^a^b^c^d...=y即 a^b^c^d...=x^y所以直接宽搜结果,O(1)查询。

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 0x3fffffffffffffff

const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;

int n, m;
int val[20], dis[1 << 17];
queue<int>qu;

void cal()
{
    int i, j, k, s;
    memset(dis, -1, sizeof(dis));
    while (!qu.empty())qu.pop();

    dis[0] = 0;
    qu.push(0);
    while (!qu.empty())
    {
        int k = qu.front();
        qu.pop();

        for (i = 0; i < 17; i++)
        {
            s = k ^ (1 << i);
            if (dis[s] == -1)
            {
                dis[s] = dis[k] + 1;
                qu.push(s);
            }
        }
        for (i = 1; i <= n; i++)
        {
            s = k^val[i];
            if (dis[s] == -1)
            {
                dis[s] = dis[k] + 1;
                qu.push(s);
            }
        }
    }
}

void solve()
{
    int i, j, k;
    int u, v;

    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &val[i]);
    }
    
    cal();
    
    ll ans = 0, res;
    for (k = 1; k <= m; k++)
    {
        scanf("%d%d", &u, &v);
        res = dis[u^v];
        ans = (ans + (ll)(res*k)%mod) % mod;
    }
    printf("%lld\n", ans);
}

int main()
{
#ifndef ONLINE_JUDGE  
    freopen("i.txt", "r", stdin);
    freopen("o.txt", "w", stdout);
#endif 

    int t;
    scanf("%d", &t);
    while (t--)
    {
        solve();
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值