CF557D Vitaly and Cycle 题解
前置
第一次独立做出来 *2000 的题,肯定是 cf 评分评高了。
题意简述
给定一个
解题思路
不难发现最多加
具体地说,我们分以下几种情况:
-
m=0
这时候必须加
- 存在奇环
此时答案为 0 1。主要讲一下如何判断奇环。我们给 dfs 一个参数
- 存在一个连通块包含至少三个点
这个时候我们只需要连
如何统计连边方案数?我们从连通块中任意一个点出发,对整个块黑白染色,连的这一条边要么是黑点和黑点,要么是白点和白点,直接 dfs 统计黑点白点数量然后计算即可。
- 其余情况
这个时候我们需要连
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,vis[200010],cnt_0=0,cnt_1=0,ans=0,num[200010],flg=0;
vector<int> G[200010];
void dfs(int x,int len){
if(vis[x]){
if(len-num[x]>=3&&(len-num[x])%2){
cout<<"0 1"<<endl;
exit(0);
}
return;
}
vis[x]=1,num[x]=len;
if(num[x]%2) cnt_1++;
else cnt_0++;
for(int v:G[x]) dfs(v,len+1);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
if(m==0) return cout<<"3 "<<n*(n-1)*(n-2)/6<<endl,0;
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(!vis[i]){
cnt_0=cnt_1=0;
dfs(i,0);
if(cnt_0>1||cnt_1>1) flg=1;
ans=ans+cnt_0*(cnt_0-1)/2;
ans=ans+cnt_1*(cnt_1-1)/2;
}
}
if(flg) cout<<"1 "<<ans<<endl;
else cout<<"2 "<<m*(n-2)<<endl;
return 0;
}