noi 2007 生成树计数 矩阵乘法

题意:
  有一个N个顶点的无向图,N个顶点编号为1~N。点i与点j之间有一条无向边当且仅当|i-j|<=k,求这个无向图的生成树个数mod 65521的值。


思路:以连续k个点的连通情况作为状态


  1 #include<iostream>
2 #include<map>
3 #include<string>
4 using namespace std;
5 #define mod 65521
6 long long n;
7 int m,t,top;
8 map <int,int> home;
9 struct matrix
10 {
11 long long a[60][60];
12 matrix(){ memset(a,0,sizeof(a)); }
13 };
14 matrix graph;
15 struct Edge
16 {
17 int l,r;
18 }edge[11];
19 int c[10];
20 int f[10],hash[100],temp[10],vector[101],used[10];
21 bool use[11];
22 matrix operator *(const matrix &x,const matrix &y)
23 {
24 int i,j,k;
25 matrix ans;
26 for(i=1;i<=top;i++)
27 for(j=1;j<=top;j++)
28 for(k=1;k<=top;k++)
29 {
30 ans.a[i][j]+=x.a[i][k]*y.a[k][j];
31 if(ans.a[i][j]>=mod) ans.a[i][j]%=mod;
32 }
33 return ans;
34 }
35 int find(int x)
36 {
37 return f[x]==-1?x:f[x]=find(f[x]);
38 }
39 bool merge(int x,int y)
40 {
41 if(find(x)==find(y)) return 1;
42 f[find(x)]=find(y); return 0;
43 }
44 void dfs(int i)
45 {
46 if(i==m*(m-1)/2+1)
47 {
48 memset(f,0xff,sizeof(f));
49 if(t>=m) return ;
50 int j,k,ten=1,c=0;
51 for(j=1;j<=m*(m-1)/2;j++)
52 if(use[j]&&merge(edge[j].l,edge[j].r)) return ;
53 for(j=1;j<m;j++) ten*=10;
54 for(j=1;j<=m;j++)
55 {
56 for(k=1;k<=j;k++)
57 if(find(k)==find(j))
58 {
59 c+=k*ten; break;
60 }
61 ten/=10;
62 }
63 if(home[c]!=0) return ;
64 home[c]=++top; hash[top]=c;
65 return ;
66 }
67 dfs(i+1);
68 use[i]=1; t++;
69 dfs(i+1);
70 use[i]=0; t--;
71 }
72 void dfs2(int i,int c[],int x)
73 {
74 if(i==m+1)
75 {
76 int j,k,ten=1,y=0,first;
77 for(j=1;j<=m;j++) temp[j]=c[j];
78 memset(f,0xff,sizeof(f));
79 for(j=1;j<=m;j++) merge(j,c[j]);
80 for(j=1;j<=m;j++)
81 if(use[j]&&merge(c[j],m+1)) return ;
82 for(first=2;first<=m+1;first++)
83 if(find(1)==find(first)) break;
84 if(first==m+2) return ;
85
86 if(find(m+1)==m+1) c[m+1]=m+1;
87 else c[m+1]=c[find(m+1)];
88 for(j=2;j<=m+1;j++)
89 if(c[j]==1) c[j]=first;
90
91 for(j=1;j<m;j++) ten*=10;
92 for(j=2;j<=m+1;j++)
93 {
94 for(k=2;k<=j;k++)
95 if(find(k)==find(j))
96 {
97 y+=(k-1)*ten; break;
98 }
99 ten/=10;
100 }
101 for(j=1;j<=m;j++) c[j]=temp[j];
102 graph.a[x][home[y]]++;
103 return ;
104 }
105
106 dfs2(i+1,c,x);
107 use[i]=1;
108 dfs2(i+1,c,x);
109 use[i]=0;
110 }
111
112 void build_matrix()
113 {
114 int i,j;
115 for(i=1;i<=top;i++)
116 {
117 vector[i]=1;
118 memset(use,0,sizeof(use));
119 memset(used,0,sizeof(used));
120 int x=hash[i];
121 for(j=1;j<=m;j++)
122 {
123 c[m-j+1]=x%10; x/=10;
124 used[c[m-j+1]]++;
125 }
126 for(j=1;j<=m;j++)
127 {
128 if(used[j]==3) vector[i]=3;
129 if(used[j]==4) vector[i]=16;
130 if(used[j]==5) vector[i]=125;
131 }
132 dfs2(1,c,i);
133 }
134 }
135 int matrix_pow()
136 {
137 n=n-m;
138 int i,j;
139 int des=0,ten=1;
140 for(i=1;i<=m;i++)
141 {
142 des+=ten;
143 ten=ten*10;
144 }
145 matrix ans;
146 for(i=1;i<=top;i++) ans.a[i][i]=1;
147 while(n>0)
148 {
149 if(n&1) ans=ans*graph;
150 graph=graph*graph;
151 n>>=1;
152 }
153 int sum=0;
154 for(i=1;i<=top;i++) sum+=vector[i]*ans.a[i][home[des]];
155 return sum%mod;
156 }
157 int main()
158 {
159 freopen("count.in","r",stdin);
160 freopen("count.out","w",stdout);
161 memset(use,0,sizeof(use));
162 cin>>m>>n;
163 int i,j;
164 top=0;
165 for(i=1;i<=m;i++)
166 for(j=i+1;j<=m;j++)
167 {
168 edge[++top].l=i; edge[top].r=j;
169 }
170 top=t=0;
171 dfs(1);
172 build_matrix();
173 cout<<matrix_pow()<<endl;
174 return 0;
175 }



原文地址:https://www.cnblogs.com/myoi/p/2389505.html