【题意分析】

  给你一张特殊的,被称为“轮状基”的无向图,求其生成树个数。

【解题思路】

引理:

  基尔霍夫矩阵

基尔霍夫矩阵=度数矩阵-邻接矩阵(邻接矩阵权=两点连边数)

  Matrix-Tree定理

对于任意一个无向图,其生成树个数为其基尔霍夫矩阵的任意一个余子式的行列式值。

算法一:

  直接暴力构图,用Matrix-Tree定理算出生成树个数,复杂度O(n3),理论可过,但考虑到高精度。。

  附上一个算矩阵行列式的小公举工具。

算法二:

  听说这个图很特殊,那一定有一些特殊性质?

  先写出这个基尔霍夫矩阵的一般形态:

  答案就是他的任意一个代数余子式的行列式值,为了最简化问题,我们可以去掉第一行第一列:

  那么只要求这个矩阵的行列式值就可以了。

  我们先初等变换一下:

  这样答案就等于这个矩阵的行列式值前面加个符号,即乘上(-1)n-1

  寻找这个矩阵行列式计算的规律,发现对倒数第二行进行高斯消元:

  可得递推式组:

  • Fi=Gi-1+3*Fi-1
  • Gi=-Fi-1

  整理后即Fi=3*Fi-1-Fi-2(边界F1=-1,F2=-3)

  于是可以矩阵可以变换为这种形式:

  同理,对倒数第一行进行高斯消元,矩阵最终变为:

  其行列式为:(-1)n-2*f*(i-g*h/f)=(-1)n-2*(f*i-g*h)

  则原行列式值为:(-1)2n-3*(f*i-g*h)=g*h-f*i

  带入各函数,结合关于行列式的FH定理,展开得:Hn+Fn-1-2

  设原式=Rn,可得递推式:Rn=3*Rn-1-Rn-2+2(R1=2,R2=5)

  这就是答案递推式了,复杂度O(n)。

  恩,更详尽的证明,让vfk带你飞!

算法三:

  打表找规律!(听说这就是我当初把这题当成高精度练习题的理由)

  设Fi=3*Fi-2-Fi-4,则当i为奇数时,ansi=Fi2,当i为偶数时,ansi=5*Fi2

  复杂度O(n)

【参考程序】

//听说我写这题时我还没有听说过一个叫做Py的东西。。QAQ

//这个板子还有可能是错的。。QAQ

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#define REP(I,start,end) for(int I=start;I<=end;I++)
#define PER(I,start,end) for(int I=start;I>=end;I--)
using namespace std;
long long digiter=100000000ll;
inline void init(long long initer)
{
digiter=initer;
}
struct bigNumber
{
int len;
long long num[];
inline void operator =(long long T)
{
memset(num,,sizeof(num));
len=;
while(T)
{
num[++len]=T%digiter;
T/=digiter;
}
}
bool positive()
{
return len&&num[len]>;
}
bool odd()
{
return num[]&;
}
inline bool operator ==(const bigNumber& T)const
{
if(len!=T.len)
return false;
REP(i,,len)
if(num[i]!=T.num[i])
return false;
return true;
}
inline bool operator >(const bigNumber& T)const
{
if(len<T.len)
return false;
if(len>T.len)
return true;
PER(i,len,)
{
if(num[i]<T.num[i])
return false;
if(num[i]>T.num[i])
return true;
}
return false;
}
inline bool operator >=(const bigNumber& T)const
{
if(len<T.len)
return false;
if(len>T.len)
return true;
PER(i,len,)
{
if(num[i]<T.num[i])
return false;
if(num[i]>T.num[i])
return true;
}
return true;
}
inline bool operator <(const bigNumber& T)const
{
if(len>T.len)
return false;
if(len<T.len)
return true;
PER(i,len,)
{
if(num[i]>T.num[i])
return false;
if(num[i]<T.num[i])
return true;
}
return false;
}
inline bool operator <=(const bigNumber& T)const
{
if(len>T.len)
return false;
if(len<T.len)
return true;
PER(i,len,)
{
if(num[i]>T.num[i])
return false;
if(num[i]<T.num[i])
return true;
}
return true;
}
inline void operator +=(const long long TT)
{
long long T=TT;
int i=;
while(T)
{
num[i]+=T%digiter;
T/=digiter;
i++;
}
REP(i,,len)
{
num[i+]+=num[i]/digiter;
num[i]%=digiter;
}
while(num[len+])
len++;
}
inline void operator -=(const long long TT)
{
long long T=TT;
int i=;
while(T)
{
num[i]-=T%digiter;
T/=digiter;
i++;
}
REP(i,,len)
while(num[i]<0ll)
{
num[i+]--;
num[i]+=digiter;
}
while(len&&num[len]==0ll)
len--;
}
inline void operator *=(const long long T)
{
REP(i,,len)
num[i]*=T;
REP(i,,len)
{
num[i+]+=num[i]/digiter;
num[i]%=digiter;
}
while(num[len+])
{
len++;
num[len+]+=num[len]/digiter;
num[len]%=digiter;
}
}
inline void operator /=(const long long T)
{
long long rest=0ll;
PER(i,len,)
{
rest=rest*digiter+num[i];
num[i]=rest/T;
rest%=T;
}
while(len&&num[len]==0ll)
len--;
}
}f[],three;
inline bigNumber operator +(const bigNumber A,const bigNumber B)
{
bigNumber C;
memset(C.num,,sizeof(C.num));
C.len=max(A.len,B.len);
REP(i,,C.len)
C.num[i]=A.num[i]+B.num[i];
REP(i,,C.len)
{
C.num[i+]+=C.num[i]/digiter;
C.num[i]%=digiter;
}
while(C.num[C.len+])
{
C.len++;
C.num[C.len+]+=C.num[C.len]/digiter;
C.num[C.len]%=digiter;
}
return C;
}
inline bigNumber operator -(const bigNumber A,const bigNumber B)
{
bigNumber C;
memset(C.num,,sizeof(C.num));
C.len=max(A.len,B.len);
REP(i,,C.len)
C.num[i]=A.num[i]-B.num[i];
REP(i,,C.len)
while(C.num[i]<)
{
C.num[i+]--;
C.num[i]+=digiter;
}
while(C.len&&C.num[C.len]==)
C.len--;
return C;
}
inline bigNumber operator *(const bigNumber A,const bigNumber B)
{
bigNumber C;
memset(C.num,,sizeof(C.num));
C.len=A.len+B.len-;
REP(i,,A.len)
REP(j,,B.len)
{
C.num[i+j-]+=A.num[i]*B.num[j];
C.num[i+j]+=C.num[i+j-]/digiter;
C.num[i+j-]%=digiter;
}
while(C.num[C.len+])
{
C.len++;
C.num[C.len+]+=C.num[C.len]/digiter;
C.num[C.len]%=digiter;
}
while(C.num[C.len]==)
C.len--;
return C;
}
inline long long operator %(const bigNumber A,const long long B)
{
long long T=;
PER(i,A.len,)
T=(T*digiter+A.num[i])%B;
return T;
}
inline bigNumber gcd(const bigNumber AA,const bigNumber BB)
{
bigNumber C,A=AA,B=BB;
while(B.positive())
{
C=A;
while(C>=B)
C=C-B;
A=B;
B=C;
}
return A;
}
inline bigNumber sqr(const bigNumber T)
{
return T*T;
}
inline bigNumber power(const bigNumber A,const int B)
{
stack<bool> isODD;
while(!isODD.empty())
isODD.pop();
int tmp=B;
while(tmp)
{
isODD.push(tmp&);
tmp>>=;
}
bigNumber C;
C=1ll;
while(!isODD.empty())
{
C=sqr(C);
if(isODD.top())
C=C*A;
isODD.pop();
}
return C;
}
inline bigNumber fact(int n)
{
bigNumber ans;
ans=1ll;
REP(i,,n)
ans*=i;
return ans;
}
inline bigNumber max(const bigNumber A,const bigNumber B)
{
if(A>B)
return A;
return B;
}
inline bigNumber min(const bigNumber A,const bigNumber B)
{
if(A<B)
return A;
return B;
}
inline void scan(bigNumber& T)
{
memset(T.num,,sizeof(T.num));
if(digiter==10ll)
{
T.len=;
char ch=getchar();
while(ch<''||ch>'')
ch=getchar();
while(ch>=''&&ch<='')
{
T.num[++T.len]=ch-'';
ch=getchar();
}
REP(i,,T.len>>)
swap(T.num[i],T.num[T.len-i+]);
}
else
{
string st;
cin>>st;
T.len=;
long long tmp=1ll;
PER(i,st.length()-,)
{
T.num[T.len]+=(st[i]-'')*tmp;
tmp*=10ll;
if(tmp==digiter)
{
T.len++;
tmp=1ll;
}
}
if(tmp==1ll)
T.len--;
}
}
inline void print(const bigNumber T)
{
if(T.len==)
{
putchar('');
return;
}
if(digiter==10ll)
PER(i,T.len,)
putchar(char(T.num[i])+'');
else
{
printf("%lld",T.num[T.len]);
PER(i,T.len-,)
{
long long tmp=digiter/10ll;
while(tmp)
{
printf("%lld",T.num[i]/tmp%10ll);
tmp/=10ll;
}
}
}
}
int n;
int main()
{
scanf("%d",&n);
f[]=1ll;
f[]=1ll;
f[]=4ll;
f[]=3ll;
three=3ll;
REP(i,,n)
f[i]=f[i-]*three-f[i-];
f[n]=sqr(f[n]);
if(~n&)
f[n]*=5ll;
print(f[n]);
return ;
}

  和Py比较一下。。

 if __name__=="__main__":
n,last,ans=input(),1,5
if n<2:
print 2
else:
for i in xrange(n-2):
ans,last=3*ans-last+2,ans
print ans

QAQ

bzoj1002题解的更多相关文章

  1. 【BZOJ1002】[ZJOI2006]轮状病毒

    [BZOJ1002]轮状病毒 题面 bzoj 题解 统计个数显然直接矩阵树定理,找规律截这里 打标如下: #include <iostream> #include <cstdlib& ...

  2. BZOJ1002【FJOI2007】轮状病毒

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6917  Solved: 3777[Submit][Statu ...

  3. bzoj1002 生成树计数 找规律

    这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它 ...

  4. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  5. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  6. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  7. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  8. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  9. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

随机推荐

  1. Vuex白话教程第六讲:Vuex的管理员Module(实战篇)

    写在前面 这一讲是 Vuex 基础篇的最后一讲,也是最为复杂的一讲.如果按照官方来的话,对于新手可能有点难以接受,所以想了下,决定干脆多花点时间,用一个简单的例子来讲解,顺便也复习一下之前的知识点. ...

  2. _declspec(dllexport)和.def(转)

    节选自:windows下编译和使用动态库dll http://blog.eonew.cn/archives/865 Microsoft 在 Visual C++ 的 16 位编译器版本中引入了 __e ...

  3. 在CMake中启用VS2017的C++17特性

    VS2017的C++17特性默认并未开启,需要在编译参数中手动开启.找到项目的CMakeLists.txt,在查找编译器的代码后面加入如下内容即可. ") include(CheckCXXC ...

  4. spring boot 四大组件之Auto Configuration

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  5. 对Map的key按升序进行排序

    //对Map的key按升序进行排序 List<Map.Entry<Integer,Task>> mappingList = new ArrayList<Map.Entry ...

  6. IntelliJ IDEA创建Maven web项目速度慢的解决方法

    在Properties中添加Name:archetypeCatalog和Value:internal,如下图那样

  7. .net 实用小技巧

    Linq 实现in查询 Dictionary<int, IP> dict = new Dictionary<int, IP>(); dict.Add(1, new IP(&qu ...

  8. (转)OpenFire源码学习之六:用户注册

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413509 用户注册 注册流程: 1.客户端进行握手给服务端发送连接消息: <s ...

  9. python安装 cvxpy 巨坑,一堆C++错误

    https://www.lfd.uci.edu/~gohlke/pythonlibs/#ecos 下载scs,ecos,cvxpy的whl,一个个安装即可 之前被一堆C++错误搞晕了2小时

  10. 20140808 const和define区别 内联函数(inline) 栈和堆的地址分配 栈帧

    1.const和define区别 const有数据类型(不能改变的变量),define只是简单的字符串替换,没有数据类型. C++程序用const完全取代 define. const还可以类成员函数为 ...