H3PO4
2024-11-20 15:07:55
大分讨!
首先如果整个图连通,那么就不需要执行任何操作,直接输出
若图不连通,那么对某个点进行一次操作之后,它会与原来的其他所有连通块连通。此时若它仍与本来所在的连通块连通(或者它原来所在的连通块只有它一个点),那么整个图就连通了。先不考虑只有一个点的连通块。
发现所有点都不满足操作后仍与本来所在的连通块连通当且仅当原来的所有连通块都是完全图。
此时对一个点操作相当于把它从一个连通块移动到了另一个连通块,且操作后的连通块仍然是完全图。所以最优策略就是把较小的连通块的点全部移动到较大的连通块,移动的顺序任意。
设整个图的点集为
这一过程的时间复杂度为
设
操作后此连通块仍然连通,于是一次操作就让整个图连通了。
包含
显然,上述论证表明合法的点(一次操作后整个图连通)一定存在。这一判断过程的时间复杂度为 Tarjan 算法的复杂度加上割点的度数和,即
设
因为有重边,所以需要去重。我用的是 std::sort
然后 std::unique
,时间复杂度
总时间复杂度
代码大量滥用了 lambda,写的很丑,仅供参考。
#include<bits/stdc++.h>
using I=int;
template<class T>using V=std::vector<T>;
template<class T,I N>using A=std::array<T,N>;
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define all(x) bg(x),ed(x)
const I MOD=1e9+7;
int main(){
std::cin.tie(0)->sync_with_stdio(0);
I n,m;std::cin>>n>>m;
V<V<I>>g(n);
for(I i=0;i<m;i++){
I u,v;std::cin>>u>>v;u--;v--;
g[u].push_back(v);g[v].push_back(u);
}
for(auto&e:g){
std::sort(all(e));
e.erase(std::unique(all(e)),ed(e));
}
V<I>fac(n+1);
fac[0]=1;for(I i=1;i<=n;i++)fac[i]=1ll*i*fac[i-1]%MOD;
V<I>vis(n,-1);V<V<I>>pts;
auto dfs=[&](auto&&dfs,I u,I c)->void{
vis[u]=c;pts[c].push_back(u);
for(I v:g[u])if(vis[v]==-1)dfs(dfs,v,c);
};
I col=0;
for(I i=0;i<n;i++)if(vis[i]==-1)pts.push_back({}),dfs(dfs,i,col++);
if(col==1){std::cout<<"0\n1\n";return 0;}
I minz=1e9,nmz=0,w=0,w2=0,allcc=1;
for(I i=0;i<col;i++){
if([&]{for(I u:pts[i])if(g[u].size()!=pts[i].size()-1)return 0;return 1;}()){
if(pts[i].size()==1)w2++;
if(I z=pts[i].size();z<minz)minz=z,nmz=1;
else if(z==minz)nmz++;
}else{
allcc=0;
I root=pts[i][0];
V<I>dfn(n,-1),low(n,-1),cut(n),bl(n,-1),sta;
V<V<I>>dcc;
I bc=0;
auto tarjan=[&](auto&&tarjan,I u)->void{
dfn[u]=low[u]=bc++;sta.push_back(u);
int f=0;
for(I v:g[u]){
if(dfn[v]!=-1)low[u]=std::min(low[u],dfn[v]);
else{
tarjan(tarjan,v);
low[u]=std::min(low[u],low[v]);
if(low[v]>=dfn[u]){
if(++f>1||u!=root)cut[u]=1;
dcc.push_back({});
while(1){
I t=sta.back();sta.pop_back();
dcc.back().push_back(t);
bl[t]=dcc.size()-1;
if(t==v)break;
}
dcc.back().push_back(u);
bl[u]=dcc.size()-1;
}
}
}
};
tarjan(tarjan,root);
V<V<I>>nr(n);
for(I z=0;auto&cc:dcc){
I t=0,w;
for(I u:cc)if(cut[u])t++,w=u;
if(t==1)nr[w].push_back(z);
z++;
}
for(I u:pts[i])if(g[u].size()!=pts[i].size()-1){
I ow=w;
if(cut[u]){
if(nr[u].empty())w++;
else
w+=[&](){
for(I i:nr[u]){
I t=0;
for(I v:g[u])if(bl[v]==i)t++;
if(t==dcc[i].size()-1)return 0;
}
return 1;
}();
}else w++;
}
}
}
if(allcc){
if(col==2||minz==1)std::cout<<minz<<'\n'<<1ll*nmz*fac[minz]%MOD<<'\n';
else{
I w=0;
for(I i=0;i<col;i++)w=(w+1ll*pts[i].size()*(n-pts[i].size())%MOD)%MOD;
if(minz==2)w+=2*nmz;
std::cout<<"2\n"<<w%MOD<<'\n';
}
return 0;
}
std::cout<<"1\n"<<w+w2<<"\n";
}