这个题可以用矩阵树定理,构造基尔霍夫矩阵,然后直接求行列式。。
但这样做会被卡精度,所以需要考虑有没有递推的做法
首先想按联通块个数来分状态,但除个数外,还有每个联通块的大小也会影响答案,
所以这是不能离散的,然后枚举是n!,,然后尝试打表找规律,发现奇数个都是二次方,偶数个都是5*二次方
然后把它们列下来会发现前两项是1,下一项是3,自然想到斐波那契,然后我就考虑差值了,偶数直接是项,但并没有想到奇数怎么算
然后正解是利用行列式的性质进行行行相减,然后减成一个递推式:
码(高精写得好熟啊):
#include<iostream>
#include<cstdio>
using namespace std;
int n,f[105][2005],i,j,jw;
int main()
{
scanf("%d",&n);
f[1][1]=f[1][0]=f[2][0]=1;
f[2][1]=5;
for(i=3;i<=n;i++)
{
f[i][0]=f[i-1][0];
jw=0;
for(j=1;j<=f[i-1][0];j++)
{
int lin=jw;
jw=(f[i-1][j]*3+lin)/10;
f[i][j]=(f[i-1][j]*3+lin)%10;
}
if(jw>0)f[i][++f[i][0]]=jw;
jw=0;
for(j=1;j<=f[i][0];j++)
{
f[i][j]=f[i][j]-f[i-2][j]-jw;
jw=0;
if(f[i][j]<0)f[i][j]+=10,jw=1;
}
while(f[i][f[i][0]]==0)f[i][0]--;
f[i][1]+=2;
for(j=1;j<=f[i][0];j++)
{
if(f[i][j]>=10)f[i][j]-=10,f[i][j+1]++;
}
if(f[i][f[i][0]+1]>0)f[i][0]++;
}
for(i=f[n][0];i>=1;i--)
printf("%d",f[n][i]);
}