题目大意
求给定点数的最小生成树的个数。
题解
看到大家的题解中都用到了基尔霍夫矩阵,但是我用的是不太主流的一种dp。既把环处理为两部分,对于一条完整的链进行dp,对于另一部分用乘法原理进行统计。
题解:http://z55250825.blog.163.com/blog/static/150230809201411692636459/
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int maxd=2000;
struct INT {
int v[200],len;
INT() {}
INT(int x) {
for(len=0;x;x/=10) v[++len]=x%10;
return;
}
inline INT operator * (const INT &b) const {
register INT res; res.len=0;
register int i,j;
for(i=0;i<=len+b.len;++i) res.v[i]=0;
for(i=1;i<=b.len;++i) {
for(j=1;j<=len;++j) {
int sco=b.v[i]*v[j];
res.v[i+j-1]+=sco%10;
res.v[i+j]+=sco/10;
}
}
for(i=1;i<=len+b.len;++i) if(res.v[i]>=10) {
res.v[i+1]+=res.v[i]/10;
res.v[i]%=10;
}
for(i=len+b.len;i;--i) if(res.v[i]) {
res.len=i;
break;
}
return res;
}
inline INT operator - (const INT &b) const {
register INT res; res.len=0;
register int i;
for(i=1;i<=len;++i) res.v[i]=v[i];
for(i=1;i<=b.len;++i) {
res.v[i]-=b.v[i];
if(res.v[i]<0) {res.v[i]+=10, --res.v[i+1];}
}
for(i=len;i;--i) if(res.v[i]) {
res.len=i;
break;
}
return res;
}
inline INT operator + (const INT &b) const {
register INT res; res.len=0;
register int i;
for(i=1;i<=max(len,b.len)+5;++i) res.v[i]=0;
for(i=1;i<=len;++i) res.v[i]=v[i];
for(i=1;i<=b.len;++i) {
res.v[i]+=b.v[i];
if(res.v[i]>=10) {res.v[i+1]+=res.v[i]/10; res.v[i]%=10;}
}
for(i=1;i<=max(b.len,len)+1;++i) if(res.v[i]>=10) {
res.v[i]-=10;
res.v[i+1]+=1;
}
for(i=max(len,b.len)+1;i;--i) if(res.v[i]) {
res.len=i;
break;
}
return res;
}
void print() {
if(len==0) {printf("0\n"); return;}
for(int i=len;i;--i) printf("%d",v[i]);
printf("\n");
}
}f[105];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif // ONLINE_JUDGE
f[0]=INT(1), f[1]=INT(1), f[2]=INT(3);
for(int i=3;i<=100;i++) {
f[i]=(f[i-1]*INT(3))-f[i-2];
}
int n;
scanf("%d",&n);
INT ans(0);
for(int L=1;L<=n;L++) {
INT x(L);
ans=ans+x*x*f[n-L];
}
ans.print();
return 0;
}