Codeforces方向
Luogu方向
首先可以用一个类似拓扑排序的方法(把度数为 0 0 0 加入变为度数小于 2 2 2 就加入)把所有可能被选择的点找出来
其中不可能选择的点不一定只有环上的点,也可能是类如连了多个不同的环的点
可以发现,对于可以被选择的点一定构成了多棵树
为什么不可能有多于 1 1 1 个点于环上的点相邻?因为这几个点之间的路径就永远不可能被删
所以可以把树分为 2 2 2 种:
时间复杂度为 O ( n 3 ) O(n^3) O(n3)
#include
using namespace std;
typedef long long LL;
const int N(110),M(10100),P(1e9+9);
int n,m,rt,cnt;
int deg[N],ans[N],C[N][N];
int f[N][N],t[N],siz[N],Tt[N];
bool ok[N],vis[N];
int e[M],h[N],ne[M],idx;
int hh,tt=-1,que[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs1(int u){
vis[u]=1,cnt++;
for(int i=h[u];~i;i=ne[i]) if(!ok[e[i]]) rt=u;
for(int i=h[u];~i;i=ne[i]) if(!vis[e[i]]&&ok[e[i]]) dfs1(e[i]);
}
void dfs2(int u,int fa){
memset(f[u],0,sizeof(f[u]));
f[u][0]=1,siz[u]=0;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
if(!ok[v]||v==fa) continue;
dfs2(v,u);
for(int j=0;j<=siz[u]+siz[v];j++) t[j]=0;
for(int j=0;j<=siz[u];j++) for(int k=0;k<=siz[v];k++) (t[j+k]+=(LL)f[u][j]*f[v][k]%P*C[j+k][j]%P)%=P;
siz[u]+=siz[v];
for(int j=0;j<=siz[u];j++) f[u][j]=t[j];
}
siz[u]++,f[u][siz[u]]=f[u][siz[u]-1];
}
void dfs3(int u,int fa){
dfs2(u,0);
for(int i=0;i<=n;i++) (Tt[i]+=f[u][i])%=P;
for(int i=h[u];~i;i=ne[i]) if(e[i]!=fa&&ok[e[i]]) dfs3(e[i],u);
}
void merge(int rt,int *ad){
for(int j=1;j<=n;j++) t[j]=0;
for(int j=1;j<=n;j++) for(int k=0;k<=j;k++) (t[j]+=(LL)ans[k]*ad[j-k]%P*C[j][k]%P)%=P;
for(int j=1;j<=n;j++) ans[j]=t[j];
}
void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int qmi(int a,int b,int p){
int res=1;
for(;b;b>>=1){
if(b&1) res=(LL)res*a%p;
a=(LL)a*a%p;
}
return res;
}
int main(){
C[0][0]=1;
for(int i=1;i<N;i++) for(int j=0;j<=i;j++) C[i][j]=(!j||i==j)?1:(C[i-1][j]+C[i-1][j-1])%P;
n=read(),m=read();
memset(h,-1,sizeof(h));
for(int i=1,x,y;i<=m;i++){
x=read(),y=read();deg[x]++,deg[y]++;
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++) if(deg[i]<2) que[++tt]=i;
while(hh<=tt){
int u=que[hh++];ok[u]=1;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];deg[v]--;
if(!ok[v]&°[v]<2) que[++tt]=v;
}
}
ans[0]=1;
for(int i=1;i<=n;i++)
if(ok[i]&&!vis[i]){
rt=0,cnt=0,dfs1(i);
if(rt) dfs2(rt,0),merge(rt,f[rt]);//有根树
else{//无根树
memset(Tt,0,sizeof(Tt));
dfs3(i,0);
for(int j=0;j<cnt;j++) Tt[j]=(LL)Tt[j]*qmi(cnt-j,P-2,P)%P;
merge(rt,Tt);
}
}
for(int i=0;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}