0.我自己瞎想
发现图可以分为外环和内叉,外环又能分成几组,分组必须有一个叉。
那就分类讨论,当叉为 0,1,2,3......
使用组合数,先枚举环分组,再乘上每个环的点数即可。
看着好像没问题,但分完叉之后还得给环分组,数量级又得乘 n。
复杂度是 ,高精度还得乘个 100。
寄。
1.找规律
多亏瞎想大法,我们至少把1到5的数据算出来:
1,5,16,45,121......
注意到奇数项为平方数,偶数项为平方数减4。
所对应的平方数根号下为:
1,2,4,7,11......
神秘斐波那契数列。
那就有公式了:
搞定。
2.递推
主播,找规律还是太不严谨了,有没有更规范的做法?
有的有的,我们可以递推。
既然递推,那拆环为链。
枚举 和
,
比
小,
到
已计算过,而
到
是单独一组。
那么有公式:
为啥后面乘 呢,因为长度为
的环上有
个点可以被叉选到。
链的搞定了,那环我们只需要将每种情况逆时针旋转。
能旋转多少次呢?当然是第一段环的边数。
(啊这个不解释了自己画下图就知道)
那咋算呢?
这简单,上面枚举当 时,答案累计
。
原本的累计 含义是:这一段有
个点,可以有
个叉的选择。
现在的累计 含义是:和上面一样,然后整段环可以旋转
次,相当于
。
那么有公式:
复杂度 ,再乘个高精度100。
还有没有更快的做法呢?当然。
这里简述下:
断环为链都一样,但在连 1——n 这条边的时候枚举。
惊喜的发现结果可以和前面公式结合:
(啊就是分别枚举第一段环的点数然后乘法原理,不过多解释)
简缩下:
(其实就是统计 出现的次数)
复杂度,乘个高精度100。
3.矩阵树 / 基尔霍夫矩阵
主播,递推固然好,但推公式麻烦怎么办?
我们还有暴力矩阵树。
防止有同学还没学过线代,这里简单介绍下:
矩阵:数的集合,一般是方程的系数。
高斯消元:可以求线性方程的解,也能求行列式。
行列式:矩阵的值,这里我们用高斯消元直接求出来。
那么基尔霍夫矩阵又是什么东西呢?
不想知道只用记得它的行列式为生成树的个数。
基尔霍夫矩阵:当 时,
为
点的度数。
当 时,如果两点有边相连,
为
;反之为
。
生成树:在一个无向图连通中,能够连接所有顶点的树结构。
我们可以把轮状基看作初始边和点的集合,我们要做的就是找它的生成树的个数。
那直接高斯消元下基尔霍夫矩阵,求个行列式,搞定。
好吧,复杂度还是有点寄,但就当学了个有用且高大上的算法吧^^
这里只给第三种做法的90分代码,其他两种不是很难,同学们自编。
(高精除我实在不想打。。同学们学第三种打前两种就好或者用别的语言)
代码里有点注释,没学过高斯消元的同学不用怕。
#include<bits/stdc++.h>
using namespace std;
//我流快读快写
template<typename T> void qread(T &x){
x=0; int f=1; char c=getchar();
for(; !isdigit(c); c=getchar()) if(c=='-') f=-1;
for(; isdigit(c); c=getchar()) x=x*10+(c-'0');
x*=f;
}
template<typename T> void qwrite(T x){
if(x<0) printf("-"), x=-x;
if(x>9) qwrite(x/10);
putchar(x%10+'0');
}
//
const int N=110;
__int128 K[N][N], ans;
int n;
void add(int x, int y){
K[x][x]++; K[y][y]++;
K[x][y]--; K[y][x]--;
}
void gauss(){
//主要做的事情就是辗转相减两行,直到该列除特殊位外都为 0
//当然,也有浮点的做法,不过这题数据大精度问题要考虑,你忍忍不能用
int r=1; ans=1; //r记录特殊位的行(一般情况下 r=c
for(int c=1; c<=n; c++){ //枚举列
for(int i=r+1; i<=n; i++){ //特殊位下面的行
while(K[i][c]){
__int128 bs=K[r][c]/K[i][c]; //用i行的消r行
for(int j=1; j<=n; j++) K[r][j]-=K[i][j]*bs;
swap(K[r], K[i]); //交换
ans*=-1;
//不严格证明下:
//设 i行值为 a,r行值为 b
//第一步操作:i:a+b r:b
//第二步操作:i:a+b r:b-(a+b)
//第三步操作:i:a+b+(-a) r:-a
//将 r的 -a的符号提出来,整个行列式就乘了 -1
}
}
if(K[r][c]!=0) r++; //判断多解用的,一般都执行
}
for(int i=1; i<=n; i++) ans*=K[i][i];
//高斯消元完整个矩阵就变成上三角矩阵(主对角行列式),直接乘对角即可
qwrite(ans);
}
int main(){
memset(K, 0, sizeof(K));
qread(n);
//建图
for(int i=1; i<=n; i++){
add(i, n+1);
if(i==n) add(n, 1);
else add(i, i+1);
}
//
gauss();
return 0;
}
&spm=1001.2101.3001.5002&articleId=149305640&d=1&t=3&u=063a8d41fd264f599dcdf2098ba12df3)
310

被折叠的 条评论
为什么被折叠?



