列表

详情


NC25528. J.I

描述

养鸽场有 N 个鸽笼,编号为 1 ~ N 。
有些鸽笼之间有道路。一共有 M 条无向道路,并且这些道路不形成环。
两位鸽王都有自己的手下,都会管理一些鸽笼让手下住进去(手下数量无限,每个鸽笼会住进无限个手下)。他们会正好分完所有的鸽笼。
他们会先分配每个鸽笼的归属,再让手下住进去。
令鸽王们头疼的是,如果一个鸽王的两个不同鸽笼的手下之间存在一条路径,并且路径上没有对方手下的话,那么这两位就会私奔。
鸽王们虽然有无限个手下,但是私奔这种事还是让他们很生气。
现在他们想问你,在满足**存在一种鸽笼的分配方案,使得没有鸽鸽私奔**的条件下,他们最多再修建多少条道路?
新的道路不能有自环,不能有重边,不能和原道路有重边。
新的养鸽场可以有环。

输入描述

第一行两个整数 N,M
接下来 M 行,每行两个整数 u,v ,表示鸽笼 u 和鸽笼 v 之间有一条无向道路。
保证没有重边和自环。

输出描述

一行一个整数 ans ,表示最多修建多少条道路。

示例1

输入:

3 1
1 2

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 2009ms, 内存消耗: 15352K, 提交时间: 2020-07-23 08:53:14

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10;
int n,m,vis[N],cnt[3],res; bitset<N> dp;
vector<int> g[N];
void dfs(int x,int col){
	vis[x]=col;	cnt[col]++;
	for(int to:g[x]) if(!vis[to]) dfs(to,col^3);
}
signed main(){
	cin>>n>>m; dp[0]=1;
	for(int i=1,a,b;i<=m;i++) scanf("%d %d",&a,&b),g[a].push_back(b),g[b].push_back(a);
	for(int i=1;i<=n;i++)	if(!vis[i]){
		cnt[2]=cnt[1]=0;	dfs(i,1);
		dp=(dp<<cnt[1])|(dp<<cnt[2]);
	}
	for(int i=n/2;i<=n;i++) if(dp[i]){res=i;	break;}
	cout<<1LL*res*(n-res)-m;
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1834ms, 内存消耗: 15416K, 提交时间: 2020-07-28 15:53:56

#include<bits/stdc++.h>
using namespace std;

bitset<200005>T;
int i,n,m,a,b,V[200005]={0};
vector<int>R[200005];
void DFS(int x)
{
	int i,j;
	for(i=0;i<R[x].size();i++)
	{
		j=R[x][i];
		if(V[j])continue;
		V[j]=V[x]^3,DFS(j);
		if(V[j]==1)a++;
		else b++;
	}
}
int main()
{
    T[0]=1;
	scanf("%d%d",&n,&m);
    for(i=0;i<m;i++)
    {
    	scanf("%d%d",&a,&b);
    	R[a].push_back(b),R[b].push_back(a);
	}
	for(i=1;i<=n;i++)
	{
		if(V[i])continue;
		V[i]=a=1,b=0,DFS(i);
		T=(T<<a)|(T<<b);
	}
	for(i=n/2;i<=n;i++)if(T[i])break;
	printf("%lld\n",(long long)i*(n-i)-m);
    return 0;
}

上一题