ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现:
·n个结点的环的生成树个数为n。
·n个结点的完全图的生成树个数为n^(n-2)。这两个发现让小栋欣喜若狂,由此更加坚定了他继续计算生成树个数的
想法,他要计算出各种各样图的生成树数目。一天,小栋和同学聚会,大家围坐在一张大圆桌周围。小栋看了看,
马上想到了生成树问题。如果把每个同学看成一个结点,邻座(结点间距离为1)的同学间连一条边,就变成了一
个环。可是,小栋对环的计数已经十分娴熟且不再感兴趣。于是,小栋又把图变了一下:不仅把邻座的同学之间连
一条边,还把相隔一个座位(结点间距离为2)的同学之间也连一条边,将结点间有边直接相连的这两种情况统称
为有边相连,如图1所示。
小栋以前没有计算过这类图的生成树个数,但是,他想起了老师讲过的计算任意图的生成树个数的一种通用方法:
构造一个n×n的矩阵A={aij},其中
其中di表示结点i的度数。与图1相应的A矩阵如下所示。为了计算图1所对应的生成数的个数,只要去掉矩阵A的最
后一行和最后一列,得到一个(n-1)×(n-1)的矩阵B,计算出矩阵B的行列式的值便可得到图1的生成树的个数所以
生成树的个数为|B|=3528。小栋发现利用通用方法,因计算过于复杂而很难算出来,而且用其他方法也难以找到更
简便的公式进行计算。于是,他将图做了简化,从一个地方将圆桌断开,这样所有的同学形成了一条链,连接距离
为1和距离为2的点。例如八个点的情形如下:
这样生成树的总数就减少了很多。小栋不停的思考,一直到聚会结束,终于找到了一种快捷的方法计算出这个图的
生成树个数。可是,如果把距离为3的点也连起来,小栋就不知道如何快捷计算了。现在,请你帮助小栋计算这类
图的生成树的数目。

Input

包含两个整数k,n,由一个空格分隔。k表示要将所有距离不超过k(含k)的结点连接起来,n表示有n个结点。

Output

输出一个整数,表示生成树的个数。由于答案可能比较大,所以你 只要输出答案除65521 的余数即可。

从左到右处理,记录最后k个点间的连通性可以进行递推,连通情况最多有Bell(5)=52种,因此可以用矩阵乘法优化递推

#include<bits/stdc++.h>
typedef unsigned int u32;
typedef u32 mat[57][57];
const u32 P=65521;
mat c,x,y;
int N,k;
long long n;
inline u32 fix(u32 x){
    return x-(x>>16)*P;
}
void clr(mat a,u32 v){
    for(int i=1;i<=N;a[i][i]=v,++i)
    for(int j=1;j<=N;++j)
        a[i][j]=0;
}
void mul(mat a,mat b){
    clr(c,0);
    for(int i=1;i<=N;++i)
    for(int k=1;k<=N;++k)if(a[i][k])
    for(int j=1;j<=N;++j)
        c[i][j]+=fix(a[i][k]*b[k][j]);
    for(int i=1;i<=N;++i)
    for(int j=1;j<=N;++j)
        a[i][j]=c[i][j]%P;
}
int ids[33333],idp=0;
int tr[57][32],st[57],f[11],g[7][57],ed[11];
void dfs(int w,int m,int v){
    if(w==k){
        ids[v]=++idp;
        st[idp]=v;
        return;
    }
    for(int i=0;i<=m;++i)dfs(w+1,m+(i==m),v|i<<3*w);
}
void upd(int k){
    for(int i=0;i<k;++i)ed[i]=-1;
    for(int i=0,p=0;i<k;++i){
        if(ed[f[i]]<0)ed[f[i]]=p++;
        f[i]=ed[f[i]];
    }
}
void mg(int a,int b,int k){
    int z=f[b];
    for(int i=0;i<k;++i)if(f[i]==z)f[i]=f[a];
}
int main(){
    scanf("%d%lld",&k,&n);
    dfs(0,0,0);
    N=idp;
    for(int i=1;i<=idp;++i){
        for(int j=0,ab;j<(1<<k);++j){
            for(int a=0;a<k;++a)f[a]=st[i]>>a*3&7;
            ab=1;
            for(int a=0,pv=-1;a<k;++a)if(j>>a&1){
                if(pv<0)pv=a;
                else if(f[pv]==f[a])ab=0;
                else mg(pv,a,k);
            }
            if(ab){
                upd(k);
                int v=0;
                for(int a=0;a<k;++a)v|=f[a]<<a*3;
                tr[i][j]=ids[v];
            }
            
            for(int a=0;a<k;++a)f[a]=st[i]>>a*3&7;
            f[k]=k;
            ab=1;
            for(int a=0,pv=-1;a<k;++a)if(j>>a&1){
                if(f[k]==f[a])ab=0;
                else mg(k,a,k+1);
            }
            if(ab){
                ab=0;
                for(int i=1;i<=k;++i)ab|=f[0]==f[i];
                if(ab){
                    for(int i=0;i<k;++i)f[i]=f[i+1];
                    upd(k+1);
                    int v=0;
                    for(int a=0;a<k;++a)v|=f[a]<<a*3;
                    ++y[ids[v]][i];
                }
            }
        }
    }
    g[1][idp]=1;
    for(int t=1;t<k;++t){
        int L=1<<t,R=L<<1;
        for(int i=1;i<=idp;++i)if(g[t][i]){
            for(int j=L;j<R;++j){
                (g[t+1][tr[i][j]]+=g[t][i])%=P;
            }
        }
    }
    clr(x,1);
    for(n-=k;n;n>>=1,mul(y,y))if(n&1)mul(x,y);
    int ans=0;
    for(int i=1;i<=idp;++i)ans+=fix(x[1][i]*g[k][i]);
    printf("%d\n",ans%P);
    return 0;
}

 

posted on 2017-07-05 17:27  nul  阅读(409)  评论(0编辑  收藏  举报