[BZOJ1494][NOI2007]生成树计数 状压dp 并查集

1494: [NOI2007]生成树计数

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 793  Solved: 451
[Submit][Status][Discuss]

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 的余数即可。

Sample Input

3 5

Sample Output

75

HINT

 

 

 

Source

 
观察到k很小,n很大。
考虑状压dp,矩阵快速幂优化。
但是我们需要对状态进行离散化,还需有一些小技巧,可以看程序。
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<cmath>
  7 #define maxn 150
  8 #define mod 65521
  9 using namespace std;
 10 int size[10]={1,1,1,3,16,125};
 11 long long n,k;int cnt;
 12 struct data {
 13     long long mat[maxn+1][maxn+1];
 14     data() {memset(mat,0,sizeof(mat));}
 15     data operator *(const data t1) {
 16         data tp;
 17         for(int i=0;i<=cnt;i++)
 18             for(int j=0;j<=cnt;j++)
 19                 for(int k=0;k<=cnt;k++) tp.mat[i][j]+=mat[i][k]*t1.mat[k][j],tp.mat[i][j]%=mod;
 20         return tp;
 21     }
 22 }A,B;
 23 int hash[20000],sta[20000];
 24 int fa[20000];
 25 int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}
 26 void prepare(int pos,int now,int ma) {
 27     if(pos==k+1) {
 28         hash[now]=cnt++;
 29         sta[cnt-1]=now;
 30         return;
 31     }
 32     for(int i=1;i<=ma;i++) prepare(pos+1,now+(i<<(3*(pos-1))),ma+(i==ma));
 33 }
 34 int get() {
 35     int h[200];
 36     memset(h,-1,sizeof(h));
 37     int re=0;
 38     int cc=0;
 39     for(int i=2;i<=k+1;i++) {
 40         if(h[find(i)]==-1) h[find(i)]=++cc;
 41     }
 42     for(int i=2;i<=k+1;i++) {
 43         int now=h[find(i)];
 44         re+=(now<<(3*(i-2)));
 45     }
 46     return hash[re];
 47 }
 48 void build(int x,int add) {
 49     int now=sta[x];
 50     for(int i=1;i<=k+1;i++) fa[i]=i;
 51     for(int i=1;i<=k;i++) {
 52         for(int j=i+1;j<=k;j++) {
 53             if(((now>>((i-1)*3))&7)==((now>>((j-1)*3))&7)) {
 54                 int f1=find(i),f2=find(j);
 55                 if(f1!=f2) fa[f1]=f2;
 56             }
 57         }
 58     }
 59     for(int i=1;i<=k;i++) {
 60         if(add&(1<<(i-1))) {
 61             int f1=find(i),f2=find(k+1);
 62             if(f1==f2) return;
 63             fa[f1]=f2;
 64         }
 65     }
 66     bool flag=0;
 67     for(int i=2;i<=k+1;i++) {
 68         if(find(1)==find(i)) {flag=1;break;}
 69     }
 70     if(!flag) return;
 71     A.mat[get()][x]++;
 72 }
 73 data pow(data x,long long p) {
 74     data ans;
 75     for(int i=0;i<=maxn;i++) ans.mat[i][i]=1;
 76     while(p) {
 77         if(p&1) ans=ans*x;
 78         x=x*x;
 79         p>>=1;
 80          
 81     }
 82     return ans;
 83 }
 84 int main() {
 85     for(int i=0;i<=maxn;i++) B.mat[i][0]=1;
 86     scanf("%lld%lld",&k,&n);
 87     prepare(1,0,1);
 88     for(int i=0;i<cnt;i++)
 89         for(int j=0;j<(1<<k);j++) build(i,j);
 90     /*for(int i=0;i<cnt;i++) {
 91         for(int j=0;j<=k;j++) cout<<A.mat[i][j]<<' ';
 92         cout<<endl;
 93     }*/
 94     for(int i=0;i<cnt;i++) {
 95         int now=sta[i];
 96         int tmp[10]={};
 97         for(int j=1;j<=k;j++) tmp[now>>((j-1)*3)&7]++;
 98         for(int j=1;j<=k;j++) B.mat[i][0]*=size[tmp[j]];
 99     }
100      
101     A=pow(A,n-k);
102     A=A*B;
103     printf("%lld",A.mat[0][0]%mod);
104 }
View Code

 

posted @ 2017-12-06 13:42  wls001  阅读(265)  评论(0编辑  收藏  举报