- 題意(原題):
- 給出一個環,上有n個點,每相鄰兩個點都連邊,每個點與環中央一個點也有連邊。求此圖生成樹個數。
- 思路:
- 關於圖的生成樹計數問題,我們可以使用Matrix-Tree定理。
- 阮行止的博文
- 我的博文
- 但是據說這麼做會被卡精度?
- 那麼暴力打表找規律。
- 1 5 16 45 121 320 841…
- 可以看出:
- 若n爲奇數位,則f(n)=n^2
- 若n爲偶數位,則f(n)=n^2*5
- 那麼高精度做就可以了,這裏直接搬上其他人推出的遞推公式:
- f(i)=3*f(i-1)-f(i-2)+2
- 代碼:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 11000
using namespace std;
struct node
{
int len,a[MAXN];
bool f;
node()
{
len=0;f=false;memset(a,0,sizeof(a));
}
node(int x)
{
len=x;f=false;memset(a,0,sizeof(a));
}
void print()
{
if(f)printf("-");
for(int i=len;i>=1;i--)printf("%d",a[i]);
printf("\n");
}
friend node operator + (node x,node y)
{
node ans(max(x.len,y.len));
for(int i=1;i<=ans.len;i++)
{
ans.a[i]+=x.a[i]+y.a[i];
if(ans.a[i]>=10)
{
ans.a[i]-=10;ans.a[i+1]++;
}
}
if(ans.a[ans.len+1])ans.len++;
return ans;
}
friend node operator - (node x,node y)
{
bool hasSwap=false;
if(x.len==y.len)
{
for(int i=x.len;i>=1;i--)
if(x.a[i]!=y.a[i])
{
if(x.a[i]<y.a[i])hasSwap=true;
break;
}
}
else if(x.len<y.len)hasSwap=true;
node ans;
if(hasSwap)
{
swap(x,y);ans.f=true;
}
for(int i=1;i<=x.len;i++)
{
ans.a[i]+=x.a[i]-y.a[i];
if(ans.a[i]<0)
{
ans.a[i]+=10;
ans.a[i+1]--;
}
}
for(int i=x.len;i>=1;i--)
if(ans.a[i])
{
ans.len=i;break;
}
return ans;
}
friend node operator * (node x,node y)
{
node ans(x.len+y.len-1);
for(int i=1;i<=x.len;i++)
for(int j=1;j<=y.len;j++)
ans.a[i+j-1]+=x.a[i]*y.a[j];
for(int i=1;i<=ans.len;i++)
if(ans.a[i]>=10)
{
ans.a[i+1]+=ans.a[i]/10;ans.a[i]%=10;
}
if(ans.a[ans.len+1])ans.len++;
ans.f=x.f^y.f;
return ans;
}
};
node a[101];
int main()
{
int n;scanf("%d",&n);
a[1].len=1;a[1].a[1]=1;
node Num3(1),Num2(1);
Num3.a[1]=3;Num2.a[1]=2;
for(int i=2;i<=n;i++)
{
a[i]=Num3*a[i-1]-a[i-2]+Num2;
}
a[n].print();
return 0;
}