cf1874b-solution

CF1874B Solution

link

给一个暴力做法:

\(a,b,c,d,m\) 看作集合,画出一个韦恩图如下

第一,二,三个圆分别表示 \(a,b,m\),中间的区域 \(2,5\) 就是 \(a\ \text{and}\ b\)\(4,5\) 就是 \(a\ \text{and}\ m\)\(5,6\) 就是 \(b\ \text{and}\ m\)\(5\) 就是 \(a\ \text{and}\ b\ \text{and}\ m\)

我们可以以此求出 \(7\) 个区域各自表示的数(集合)。

显然这七个区域表示的集合互不相交。那么我们可以用这七个区域中的若干个表示出某个数。

现在 \((x,y)\) 初始在 \((a,b)\),用七个区域表示就是 \((\{1,2,4,5\},\{2,3,5,6\})\)

要到达 \((c,d)\),我们将表示出 \(c,d\) 的区域求出来。设 \(c,d\) 由集合 \(S,T\) 表示,这里 \(S,T\) 是由 \(1\sim7\) 的元素构成,存在某个元素表示存在韦恩图中某一块。

可以建出图,共 \(2^7\times2^7\) 个点,四种操作都能描述出一条边。

\((\{1,2,4,5\},\{2,3,5,6\})\) 开始 bfs 就能求出到每个点的最短路。

不妙的是,韦恩图中某些块可能是 \(0\)。这些块可取可不取,不会影响得到的数结果。

这样每次询问就需要枚举每种集合,复杂度乘上 \(2^{14}\)。很不妙。

好在能到达的点比较少,即从 \((\{1,2,4,5\},\{2,3,5,6\})\) 能到达的状态数比较少,大概只有 \(1500\) 个。

因此枚举每个合法状态统计答案即可。复杂度 \(1500q+2^{14}\)

注意 \(c,d\) 不一定可以被表示出来,如果与 \(7\) 个数中某个数成不完全包含状态即无解。

#include <bits/stdc++.h>
#define LL long long
#define sl(n) strlen(n)
#define endline puts("")
#define pii pair<int , int>
#define pr_q priority_queue
#define DEBUG puts("DEBUG.")
using namespace std;
const int N = 1 << 7 | 7;
const int inf = ~0u >> 2;
int dis[N][N],id[N][N];
pii st[3000];
int ct,cnt;
#define x first
#define y second
void bfs()
{
    queue<pii> q;
    q.push( pii(27 , 54) );
    memset(dis , 63 , sizeof dis),dis[27][54] = 0;
    while( !q.empty() )
    {
        pii u = q.front();
        q.pop();
        if( dis[u.x & u.y][u.y] > 1e9 )
            dis[u.x & u.y][u.y] = dis[u.x][u.y] + 1,q.push( pii(u.x & u.y , u.y) );
        if(dis[u.x | u.y][u.y] > 1e9)
            dis[u.x | u.y][u.y] = dis[u.x][u.y] + 1,q.push( pii(u.x | u.y , u.y) );
        if( dis[u.x][u.x ^ u.y] > 1e9 )
            dis[u.x][u.x ^ u.y] = dis[u.x][u.y] + 1,q.push( pii(u.x , u.x ^ u.y) );
        if( dis[u.x][u.y ^ 120] > 1e9 )
            dis[u.x][u.y ^ 120] = dis[u.x][u.y] + 1,q.push( pii(u.x , u.y ^ 120) );
    }
    for(int i = 0;i < 128;i++)
        for(int j = 0;j < 128;j++)
            if( dis[i][j] < 1e9)
                id[i][j] = ++cnt,st[cnt] = pii(i , j);
}
int w[8];
void print(int v)
{
    if(v >= 2)
        print(v / 2);
    putchar(v % 2 + '0');
}
int main()
{
    cin >> ct;
    bfs();
    while(ct--)
    {
        int a,b,c,d,m;
        scanf("%d%d%d%d%d" , &a , &b , &c , &d , &m);
        w[5] = a & b & m;
        w[2] = (a & b) ^ w[5];
        w[4] = (a & m) ^ w[5];
        w[6] = (b & m) ^ w[5];
        w[1] = a ^ w[2] ^ w[4] ^ w[5];
        w[3] = b ^ w[2] ^ w[5] ^ w[6];
        w[7] = m ^ w[4] ^ w[5] ^ w[6];
        int s = 0,t = 0,s0 = 0,t0 = 0;
        for(int i = 1;i < 8;i++)
        {
            // print( w[i] ),putchar('\n');
            if( w[i] )
            {
                if( (w[i] & c) == w[i] )
                    c ^= w[i],s |= 1 << i - 1;
                if( (w[i] & d) == w[i] )
                    d ^= w[i],t |= 1 << i - 1;
            }
            else
                s0 |= 1 << i - 1,t0 |= 1 << i - 1;
        }
        // cout << c << " " << d << endl;
        if(c || d)
            puts("-1");
        else
        {
            int res = inf;
            for(int i = 1;i <= cnt;i++)
                if( (st[i].x & s) == s && (st[i].y & t) == t && (st[i].x - s | s0) == s0 && (st[i].y - t | t0) == t0 )
                    res = min(res , dis[st[i].x][st[i].y] );
            if(res <= 1e9)
                printf( "%d\n" , res );
            else
                puts("-1");
        }
    }
    return 0;
}
posted @ 2024-02-28 13:59  iorit  阅读(21)  评论(0)    收藏  举报