背景:
h
e
h
e
.
.
.
hehe...
hehe...
题目传送门:
https://www.luogu.org/problemnew/show/P2144
题意:
有一个类似与下图的形状,题目给出
n
n
n,表示蓝色点的数目,求生成树的方案。
思路 1 1 1:
细想一下,这不就是基尔霍夫矩阵&矩阵树定理吗。
考虑
n
≥
2
n≥2
n≥2时的的
A
,
D
A,D
A,D矩阵。
发现中间的度为
n
n
n,其余点的度均为
3
3
3。
在考虑每两个点之间的连边情况确定
A
A
A即可。
然后就可以采用高斯消元解决即可。
代码 1 1 1:
没有打高精度(只有 40 p t s 40pts 40pts)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL D[110][110],A[110][110],K[110][110];
int n;
LL Matrix_tree()//在这题中,0表示中间的点,1~n表示周的点
{
if(n==1)
{
D[0][0]=D[1][1]=1;
}
else if(n==2)
{
D[0][0]=2,D[1][1]=D[2][2]=3;
A[0][1]=A[1][0]=A[0][2]=A[2][0]=1,A[1][2]=A[2][1]=2;
}
else
{
D[0][0]=n;
for(int i=1;i<=n;i++)
{
D[i][i]=3;
A[0][i]=A[i][0]=1;
}
for(int i=2;i<=n;i++)
A[i][i-1]=A[i-1][i]=1;
A[1][n]=A[n][1]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
K[i][j]=D[i][j]-A[i][j];
LL ans=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
while(K[j][i])
{
int t=K[i][i]/K[j][i];
for(int k=i;k<=n;k++) K[i][k]-=K[j][k]*t;
for(int k=i;k<=n;k++) swap(K[i][k],K[j][k]);
ans=-1;
}
ans*=K[i][i];
}
return abs(ans);
}
int main()
{
scanf("%d",&n);
printf("%lld",Matrix_tree());
}
思路 2 2 2:
对于懒得打上一种做法的怎么办?
那就用刚才的代码打表找规律。
表如下:
1
=
1
∗
1
1=1*1
1=1∗1
5
=
5
∗
1
\quad\quad\quad\quad\quad\quad\quad\quad5=5*1
5=5∗1
16
=
4
∗
4
16=4*4
16=4∗4
45
=
5
∗
3
∗
3
\quad\quad\quad\quad\quad\quad\quad\quad45=5*3*3
45=5∗3∗3
121
=
11
∗
11
121=11*11
121=11∗11
320
=
5
∗
8
∗
8
\quad\quad\quad\quad\quad\quad\quad\quad320=5*8*8
320=5∗8∗8
841
=
29
∗
29
841=29*29
841=29∗29
2205
=
5
∗
21
∗
21
\quad\quad\quad\quad\quad\quad\quad\quad2205=5*21*21
2205=5∗21∗21
5776
=
76
∗
76
5776=76*76
5776=76∗76
15125
=
5
∗
55
∗
55
\quad\quad\quad\quad\quad\quad\quad\quad15125=5*55*55
15125=5∗55∗55
讲奇偶性分开。
容易看出奇数是某个数的平方,偶数是某个数的平方的
5
5
5倍。
寻找某个数的规律。
发现某个数其实就是
f
n
=
3
f
n
−
1
−
f
n
−
2
f_n=3f_{n-1}-f_{n-2}
fn=3fn−1−fn−2
最后分类谈论算出对应的值即可。
但是,还有没有更好的规律呢。
细细想想 (题解想想) ,设第
n
n
n个数的结果为
F
n
F_n
Fn,则有:
F
n
=
3
F
n
−
F
n
−
2
+
2
F_n=3F_n-F_{n-2}+2
Fn=3Fn−Fn−2+2。
那就更好实现了。
代码 2 2 2:
好久之前的了(懒得改)。
#include<cstdio>
#include<cstring>
struct node{int a[1001];int l;node(){memset(a,0,sizeof(a));}} f[101];
int n;
node jia(node x)
{
x.a[1]+=2;
for(int i=1;i<=x.l;i++)
{
x.a[i+1]+=x.a[i]/10;
x.a[i]%=10;
}
x.l++;
while(x.l>0&&x.a[x.l]==0)
x.l--;
return x;
}
node jian(node x,node y)
{
node z;
for(int i=1;i<=x.l;i++)
{
z.a[i]=x.a[i]-y.a[i];
if(z.a[i]<0)
{
x.a[i+1]--;
z.a[i]+=10;
}
}
z.l=x.l;
while(z.l>0&&z.a[z.l]==0)
z.l--;
return z;
}
node cheng(node x)
{
node y;
for(int i=1;i<=x.l;i++)
{
y.a[i]+=x.a[i]*3;
y.a[i+1]+=y.a[i]/10;
y.a[i]%=10;
}
y.l=x.l+1;
while(y.l>0&&y.a[y.l]==0)
y.l--;
return y;
}
int main()
{
scanf("%d",&n);
f[0].a[1]=0;f[0].l=1;
f[1].a[1]=1;f[1].l=1;
for(int i=2;i<=n;i++)
f[i]=jia(jian(cheng(f[i-1]),f[i-2]));
for(int i=f[n].l;i>=1;i--)
printf("%d",f[n].a[i]);
}