标签:mod mat and int 假设 span while scan 个数
题目大意:
题解:首先,我们很明显可以对于每一个连通块单独考虑。
我们先假设这个连通块是一个有根树(即根若要删除的话必须是最后一个删掉)。
那么可以做一个树形DP,令\(f_{i,j}\)表示以节点\(i\)为根的子树中,选择\(j\)个节点的方案数。
对于每一个节点,做一遍背包再乘一个组合数就可以了。
再对每一个连通块分情况讨论:
最后,把所有的状态再背包一下,背包时乘一个组合数就结束了。
下面是代码:
#include <cstdio>
#include <cstring>
const int Maxn=100;
const int Mod=1000000009;
int quick_power(int a,int b){
int ans=1;
while(b){
if(b&1){
ans=1ll*ans*a%Mod;
}
b>>=1;
a=1ll*a*a%Mod;
}
return ans;
}
int n,m;
int C[Maxn+5][Maxn+5];
void init(){
C[0][0]=1;
for(int i=1;i<=Maxn;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;
}
}
}
int head[Maxn+5],arrive[Maxn*Maxn*2+5],nxt[Maxn*Maxn*2+5],tot;
int deg[Maxn+5];
void add_edge(int from,int to){
arrive[++tot]=to;
nxt[tot]=head[from];
head[from]=tot;
}
int col[Maxn+5],col_tot;
bool un_vis[Maxn+5];
bool vis[Maxn+5],in[Maxn+5];
int que[Maxn+5],que_f,que_t;
void work_1(int S){
memset(in,0,sizeof in);
que_f=1;
que_t=0;
que[++que_t]=S;
in[S]=1;
while(que_f<=que_t){
int u=que[que_f++];
for(int i=head[u];i;i=nxt[i]){
int v=arrive[i];
if(in[v]){
continue;
}
in[v]=1;
que[++que_t]=v;
}
}
que_f=1,que_t=0;
for(int i=1;i<=n;i++){
if(in[i]&°[i]<=1){
que[++que_t]=i;
}
}
while(que_f<=que_t){
int u=que[que_f++];
vis[u]=1;
for(int i=head[u];i;i=nxt[i]){
int v=arrive[i];
deg[v]--;
if(deg[v]==1){
que[++que_t]=v;
}
}
}
for(int i=1;i<=n;i++){
if(in[i]&&(!vis[i])){
vis[i]=1;
un_vis[i]=1;
}
}
}
int sz[Maxn+5];
int f[Maxn+5][Maxn+5];
void work_2(int u,int fa){
memset(f[u],0,sizeof f[u]);
f[u][0]=1;
sz[u]=0;
for(int i=head[u];i;i=nxt[i]){
int v=arrive[i];
if(v==fa||un_vis[v]){
continue;
}
work_2(v,u);
for(int j=sz[u];j>=0;j--){
for(int k=sz[v];k>0;k--){
f[u][j+k]=(f[u][j+k]+1ll*f[u][j]*f[v][k]%Mod*C[j+k][k]%Mod)%Mod;
}
}
sz[u]+=sz[v];
}
f[u][sz[u]+1]=f[u][sz[u]];
sz[u]++;
}
int locked[Maxn+5];
bool m_r[Maxn+5];//must be the root
void work_3(int S,int c){
que_f=1,que_t=0;
que[++que_t]=S;
while(que_f<=que_t){
int u=que[que_f++];
col[u]=c;
for(int i=head[u];i;i=nxt[i]){
int v=arrive[i];
if(un_vis[v]){
locked[c]=u;
m_r[u]=1;
continue;
}
if(col[v]){
continue;
}
que[++que_t]=v;
}
}
}
int g[Maxn+5][Maxn+5];
int ans[Maxn+5];
int main(){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
deg[u]++,deg[v]++;
add_edge(u,v);
add_edge(v,u);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
work_1(i);
}
}
memset(f,-1,sizeof f);
ans[0]=1;
for(int i=1;i<=n;i++){
if(!un_vis[i]&&col[i]==0){
work_3(i,++col_tot);
if(locked[col_tot]){
work_2(locked[col_tot],0);
for(int j=0;j<=n;j++){
g[col_tot][j]=f[locked[col_tot]][j];
}
}
else{
int num=0;
for(int j=1;j<=n;j++){
if(col[j]==col_tot){
num++;
work_2(j,0);
for(int k=0;k<=sz[j];k++){
g[col_tot][k]=(g[col_tot][k]+f[j][k])%Mod;
}
}
}
for(int j=0;j<num;j++){
g[col_tot][j]=1ll*g[col_tot][j]*quick_power(num-j,Mod-2)%Mod;
}
}
for(int k=n;k>0;k--){
for(int j=k;j>0;j--){
ans[k]=(ans[k]+1ll*ans[k-j]*g[col_tot][j]%Mod*C[k][j]%Mod)%Mod;
}
}
}
}
for(int i=0;i<=n;i++){
printf("%d\n",ans[i]);
}
return 0;
}
Codeforces 512D. Fox And Travelling 题解
标签:mod mat and int 假设 span while scan 个数
原文地址:https://www.cnblogs.com/withhope/p/12909969.html