【HDU5637 BestCoder Round 74 (div1)B】【bfs预处理】Transform 15个值+17个2的幂数最小异或步数使得s变成t

Transform

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 491    Accepted Submission(s): 171


Problem Description
A list of   n  integers are given. For an integer   x  you can do the following operations:

+ let the binary representation of   x  be   b31b30...b0¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ , you can flip one of the bits.
+ let   y  be an integer in the list, you can change   x  to   xy , where    means bitwise exclusive or operation.

There are several integer pairs   (S,T) . For each pair, you need to answer the minimum operations needed to change   S  to   T .
 

Input
There are multiple test cases. The first line of input contains an integer   T   (T20) , indicating the number of test cases. For each test case:

The first line contains two integer   n  and   m   (1n15,1m105)  -- the number of integers given and the number of queries. The next line contains   n integers   a1,a2,...,an   (1ai105) , separated by a space.

In the next   m  lines, each contains two integers   si  and   ti   (1si,ti105) , denoting a query.
 

Output
For each test cases, output an integer   S=(i=1mizi) mod (109+7) , where   zi  is the answer for   i -th query.
 

Sample Input
   
   
   
   
1 3 3 1 2 3 3 4 1 2 3 9
 

Sample Output
   
   
   
   
10
Hint
$3 \to 4$ (2 operations): $3 \to 7 \to 4$ $1 \to 2$ (1 operation): $1 \oplus 3 = 2$ $3 \to 9$ (2 operations): $3 \to 1 \to 9$
 

Source
BestCoder Round #74 (div.2)


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
int a[40];
int f[1 << 17];
queue<int>q;
inline void inq(int x, int step)
{
    if (~f[x])return;
    f[x] = step;
    q.push(x);
}
void bfs()
{
    MS(f, -1); f[0] = 0;
    for (int i = 0; i <= n; ++i)inq(a[i], 1);
    while (!q.empty())
    {
        int x = q.front(); q.pop();
        for (int i = 0; i <= n; ++i)inq(x^a[i], f[x] + 1);
    }
}
void datamaker()
{
    puts("1");
    puts("15 90000"); n = 15; m = 90000;
    for (int i = 1; i < n; ++i)
    {
        printf("%d ",1<<i );
    }printf("%d\n",1<<n);
    for (int i = 1; i <= m; ++i)
    {
        printf("%d %d\n", 1, 1 ^ i);
    }
}
int main()
{
    //fre(); datamaker(); return 0;
    //0~16
    for (int i = 0; i <= 16; ++i)a[i] = 1 << i;
    scanf("%d", &casenum);
    for (casei = 1; casei <= casenum; ++casei)
    {
        scanf("%d%d", &n, &m);
        for (int i = 16+1; i <= 16+n; ++i)scanf("%d", &a[i]);
        n += 16;
        bfs();
        int ans = 0;
        for (int i = 1; i <= m; ++i)
        {
            int s, t;
            scanf("%d%d", &s, &t);
            LL v = f[s^t];
            ans = (ans + i*v) % Z;
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
【trick&&吐槽】
1e5中的二的幂数最大是1<<16==65536
于是我们可能出现的最大异或数是(1<<17)-1
数组不要开小了

【题意】
T组数据。对于每组数据——
有n个数a[],m个询问。(1<=n<=15,1<=m<=1e5)
对于每个询问,问你从s到t的最小异或步数(1<=s,t<=n)

有两种操作:
1,选择某个二进制表示反转一位
2,把x变为x^a[]

【类型】
bfs

【分析】
选择某个二进制为反转一位,其实就等价于^1 or ^2 or ^4 ...
即我们a[]可以再选择[0,16]中的一个。
即我们一共有32个数,我们求从s到t的最小异或步数

我们只要达到s^t即可。
于是我们用这32个数做bfs,求得达到某个数的最小异或步数。
然后每次输出f[s^t]即可

【时间复杂度&&优化】
O(1e5*32)

【数据】
1
2 1
65536 65535
65536 65535

*/


你可能感兴趣的:(题库-HDU,搜索-BFS)