推性质 + 网络流:ICPC2025西安K

Killing Bits - Problem - QOJ.ac

首先我们要特判掉不进行任何一次操作的情况,即:ai=bia_i=b_i

接下来我们有两个必要条件:

  • ai&bi=bia_i \& b_i=b_i
  • ∃p,  pi&bi=bi\exist p,\;p_i\& b_i=b_i

而这其实也是充要的。因为我们只需要让所有满足条件的排列 pp 都做一次操作即可。


接下来怎么判断条件2是否可行。

一个朴素的思路就是网络流,每个 pip_i 向它可以到达的 bib_i 连一条边。

然后我们可以优化建图,每个 pip_i 向 pi−2jp_i-2^j 连一条正无穷的边即可。

image-20261002154710637

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
namespace Flow {
#define int long long
struct mf_graph {
struct node {
int x, y, z, n;
};
vector<node>d;
vector<int>h, H, dep;
queue<int>q;
int k;
int u, v, w, S, T, ans=0;
void reset(int n) {
h.resize(n+5); k=1; d.resize(2);
H.resize(n+5); dep.resize(n+5);
}
void cun(int x, int y, int z) {
++k; d.pb({x, y, z, h[x]});
d[k].n=h[x]; h[x]=k;
}
void add_edge(int x, int y, int z) {
// debug("%lld -> %lld %lld\n", x, y, z);
cun(x, y, z); cun(y, x, 0);
}
int bfs() {
while(!q.empty()) q.pop();
fill(dep.begin(), dep.end(), -1);
h=H;
dep[S]=1; q.push(S);
while(!q.empty()) {
u=q.front(); q.pop();
for(int g=h[u]; g; g=d[g].n) {
v=d[g].y; w=d[g].z;
if(w<=0 || dep[v]!=-1) continue;
dep[v]=dep[u]+1; q.push(v);
}
}
return dep[T]!=-1;
}
int dfs(int x, int w) {
if(x==T) return w;
if(!w) return 0;
int ans=0, s;
for(int &i=h[x]; i; i=d[i].n) {
int y=d[i].y, z=d[i].z;
if(dep[y]!=dep[x]+1) continue;
if(z<=0) continue;
s=dfs(y, min(w, z)); ans+=s; w-=s;
d[i].z-=s; d[i^1].z+=s;
if(!w) break;
}
return ans;
}
int flow(int SS, int TT) {
S=SS; T=TT; H=h; ans=0;
while(bfs()) ans+=dfs(S, 1e18);
return ans;
}
};
#undef int
}
using namespace Flow;



//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
//#define mo
#define N 50010
int a[N], b[N], c[N], S, T, f1, f2;
int n, m, i, j, k, TT;

signed main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// srand(time(NULL));
TT = read();
while(TT--) {
n = read();
mf_graph G; G.reset(n + 1);
for(i = 1; i <= n; ++i) a[i] = read();
for(i = 1; i <= n; ++i) b[i] = read();
for(i = 1, f1 = f2 = 1; i <= n; ++i) {
f1 &= (a[i] == b[i]);
f2 &= ((a[i] & b[i]) == b[i]);
// debug("%d & %d = %d [%d %d]\n", a[i], b[i], a[i] & b[i], f1, f2);
}
if(f1) { printf("Yes\n"); continue; }
if(!f2) { printf("No\n"); continue; }
S = n; T = n + 1;
for(i = 0; i < n; ++i) {
G.add_edge(S, i, 1);
for(j = 0; j < 30; ++j)
if(i & (1 << j)) G.add_edge(i, i - (1 << j), n + 1);
}
for(i = 1; i <= n; ++i) G.add_edge(b[i], T, 1);
k = G.flow(S, T);
printf(k == n ? "Yes\n" : "No\n");
}
return 0;
}