E. Network Safety
题意:
输入
n
(
5
e
5
)
,
m
(
m
i
n
(
n
×
(
n
−
1
)
2
,
5
e
5
)
)
,
k
(
60
)
n(5e5),m(min(\frac {n\times (n-1)} 2,5e5)),k(60)
n(5e5),m(min(2n×(n−1),5e5)),k(60)
接下来一行输入
a
1
,
a
2
,
…
,
a
n
(
[
0
,
2
k
)
)
a_1,a_2,\dots,a_n([0,2^k))
a1,a2,…,an([0,2k))
接下来
m
m
m行输入
u
,
v
u,v
u,v,表示边,保证
a
u
≠
a
v
a_u\neq a_v
au=av。
问有多少个
(
A
,
x
)
(A,x)
(A,x),
A
A
A是此图的点集(可以为空),
x
(
[
0
,
2
k
)
)
x([0,2^k))
x([0,2k)),使
x
x
x和
A
A
A中每个点点值异或后,每条边两端的点值依旧不同。
题解:
首先考虑对于每个值
x
x
x分析,求有多少个子集符合要求。
a
u
≠
a
v
所
以
a
u
⨁
x
≠
a
v
⨁
x
a_u\neq a_v 所以a_u\bigoplus x\neq a_v\bigoplus x
au=av所以au⨁x=av⨁x
于是便可以分两种情况:
- a u ⨁ x ≠ a v a_u\bigoplus x\neq a_v au⨁x=av时, a v a_v av有两种选择。
- a u ⨁ x = a v a_u\bigoplus x=a_v au⨁x=av时, a v a_v av只有一种选择。
因此可以把所有的 a u ⨁ a v = x a_u\bigoplus a_v=x au⨁av=x的 u , v u,v u,v都拿出来,形成一种子图,求联通分量的个数 g g g,把 2 g 2^g 2g加入答案即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
const int N=5e5+9;
ll n,m,k,a[N];
map<ll,int>mp;
int cnt;
#define P pair<int,int>
P b[N];
vector<P>g[N];
ll ans;
int poww(int a,int b,int c){
int ans=1,base=a;
while(b){
if(b&1)ans=1ll*ans*base%c;
base=1ll*base*base%c;
b>>=1;
}
return ans;
}
int solve1(){
return 1ll*poww(2,n,mod)*(((1ll<<k)-cnt)%mod)%mod;
}
int f[N],siz[N];
int findf(int x){return f[x]==x?x:f[x]=findf(f[x]);}
int solve2(int x){
set<int>s;
for(auto i:g[x]){
int fx=findf(i.first),fy=findf(i.second);
if(fx!=fy){
f[fx]=fy,siz[fy]+=siz[fx];
}
}
int sum=0,sz=0;
for(auto i:g[x]){
if(f[i.first]==i.first&&!s.count(i.first))sum++,sz+=siz[i.first],s.insert(i.first);
if(f[i.second]==i.second&&!s.count(i.second))sum++,sz+=siz[i.second],s.insert(i.second);
}
s.clear();
for(auto i:g[x]){
f[i.first]=i.first,f[i.second]=i.second;
siz[i.first]=siz[i.second]=1;
}
return poww(2,n-sz+sum,mod);
}
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i].first>>b[i].second;
for(int i=1;i<=m;i++){
ll t=a[b[i].first]^a[b[i].second];
if(!mp.count(t))mp[t]=++cnt;
g[mp[t]].push_back(b[i]);
}
ans=solve1();
for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;
for(int i=1;i<=cnt;i++)ans=(ans+solve2(i))%mod;
cout<<ans<<endl;
return 0;
}