第十八届吉林省大学生程序设计竞赛 I 题题解
Black and White Coloring
神奇不等式
从一个神奇不等式开始,假设先手的涂色确定了 \(m_1\) 条边得分,后手随机等概率地给剩余点涂色,那么我们有得分期望如下
我们可以从这个不等式得到三个推论。
引理 1
不论先手如何染色,后手总有方法使得得分 \(X\ge\dfrac m 2\) 。
由期望定义 \(E(X)=\sum iP(x=i)\) 可得,若所有方法得分都小于 $\dfrac m 2 $ 那么得分期望一定小于 $\dfrac m 2 $ ,出现矛盾。
引理 2
要让后手染色后得分不超过 $\dfrac m 2 $ ,那么就要让后手无论如何染色得分都等于 $\dfrac m 2 $ 。
首先由引理 1 得到后手一定存在一种方法使得分 $X\ge\dfrac m 2 $ ,若还存在方法使得分 $X\lt\dfrac m 2 $ ,那么期望得分一定小于 $\dfrac m 2 $,出现矛盾。
引理 3
图上相邻节点一定不会都在先手被染色。
若图上相邻节点在先手被染色,那么 \(m_1>0\) ,$E(x)>\dfrac m 2 $ ,后手至少存在一种方法使得分超过 $\dfrac m 2 $ 。
引理 4
图上相邻节点一定不会都在后手被染色。
若图上相邻节点都在后手被染色,那么对于这两个节点的四种染色方式一定会出现其中两种得分不同,与引理 2 矛盾。
由引理 3 和引理 4 可知,图上相邻的节点会被分成先手染色 \(S\) 和后手染色 \(T\) 两个部分。
引理 5
设 \(\text{deg}_x\) 为点 \(x\) 的度数,所有 \(\text{deg}\) 为奇数的点都应该在先手被染色。
若存在点 \(x\) 在后手被染色, \(\text{deg}_x\) 为奇数。假设除 \(x\) 以外其余点被染色完成,此时 \(x\) 涂上不同颜色后得分不同,与引理 2 矛盾。
引理 6
若 \(x\in T\) 且 \(\text{deg}_x=2\) ,那么与 \(x\) 相连的两点 \(y,z\) 应该在先手被染上不同颜色。
若 \(y,z\) 在先手被染上相同颜色,那么 \(x\) 涂上不同颜色后得分不同,与引理 2 矛盾。
解法
至此,我们已经可以得到这道题的解法了。遍历原图的每个连通块,判断每个连通块是否都是二分图,存在不是二分图的连通块则无解。在联通块内部分出两部 \(A,B\) ,计算 \(\text{sum}=\text{calc}(A,B)+\text{calc}(B,A)\) 。在 \(\text{clac}(S,T)\) 这个函数中将 \(S\) 作为先手染色点集, \(T\) 作为后手染色点集。根据引理 6 ,对于 \(x\in T\) 且 \(\text{deg}_x=2\) ,将与点 \(x\) 相连的两点 \(y,z\) 相连得到边 \((y,z)\) 并加入边集 \(E\) ,得到新图 \(G(S,E)\) 。判断新图 \(G\) 是否是二分图,并统计联通块数量 \(k\) ,若是则返回 \(2^k\) ,若不是则返回 0 。最终的答案就是所有联通块的 \(\text{sum}\) 相乘。
#include<bits/stdc++.h>
using namespace std;
const int P=1e9+7;
long long qpow(long long a,long long k)
{
long long mulv=1;
while(k)
{
if(k&1)mulv=mulv*a%P;
a=a*a%P;
k>>=1;
}
return mulv;
}
void solve()
{
long long n,m,ans=1;
cin>>n>>m;
deque<bool> vis1(n+1),vis2(n+1),col1(n+1),col2(n+1);
vector<vector<int>> adj1(n+1),adj2(n+1);
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
adj1[u].push_back(v);
adj1[v].push_back(u);
}
auto calc=[&](vector<int> &S,vector<int> &T)
{
for(auto ti:T)
{
if(adj1[ti].size()&1)return 0ll;
else if(adj1[ti].size()==2)
{
int u=adj1[ti][0];
int v=adj1[ti][1];
adj2[u].push_back(v);
adj2[v].push_back(u);
}
}
bool flag=true;
auto dfs=[&](auto &&dfs,int o)->void
{
vis2[o]=true;
for(auto v:adj2[o])
{
if(vis2[v])
{
flag&=(col2[o]^col2[v]);
continue;
}
col2[v]=col2[o]^1;
dfs(dfs,v);
}
};
int cnt=0;
for(int si:S)
{
if(vis2[si])continue;
col2[si]=0;
dfs(dfs,si);
if(!flag)return 0ll;
cnt++;
}
return qpow(2,cnt);
};
for(int i=1;i<=n;i++)
{
if(vis1[i])continue;
bool flag=true;
vector<int> S,T;
auto dfs=[&](auto &&dfs,int o)->void
{
vis1[o]=true;
if(col1[o])S.push_back(o);
else T.push_back(o);
for(auto v:adj1[o])
{
if(vis1[v])
{
flag&=(col1[o]^col1[v]);
continue;
}
col1[v]=col1[o]^1;
dfs(dfs,v);
}
};
dfs(dfs,i);
if(!flag)
{
cout<<0<<"\n";
return ;
}
long long sum=calc(S,T)+calc(T,S);
ans=ans*sum%P;
}
cout<<ans<<"\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
for(int i=1;i<=T;i++)solve();
return 0;
}

浙公网安备 33010602011771号