您的位置:首页 > 其它

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

2017-12-06 13:42 309 查看

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所示。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: