cf1874b-solution
CF1874B Solution
给一个暴力做法:
把 \(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;
}

浙公网安备 33010602011771号