【题意分析】

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

【解题思路】

引理:

  基尔霍夫矩阵

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

  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. Jmeter的安装与环境配置

    1.首先从jmeter的官网http://jmeter.apache.org/download_jmeter.cgi下载jmeter,目前最新版本为5.1,支持的JDK为1.8.. 然后进行解压. 2 ...

  2. macOS免费的NTFS读写软件

    Mounty for Mac brew cask install mounty

  3. Java中udp/tcp的发送和接收

    InetAddress UDP例程: 发送数据: 接收数据: 结果: TCP例程: 发送数据: 接收数据: 结果:

  4. JavaIO流之字节流

    什么是字节? 所谓字节(Byte),是计算机数据存储的一种计量单位.一个二进制位称为比特(bit),8个比特组成一个字节,也就是说一个字节可以用于区分256个整数(0~255).由此我们可以知道,字节 ...

  5. Windows下生成目录结构树

    1.进入需要生成目录结构的文件主目录 2.在当前目录打开命令行 3.输入命令 tree /f > list.txt 4.即在当前目录下生成了list.txt文件

  6. 【LeetCode 1】两数之和

    描述 [题解] 用个map的话就是O(N)级别的了. [代码] class Solution { public: unordered_map<int,int> mymap; vector& ...

  7. NX二次开发-Block UI C++界面Specify Point(指定点)控件的获取(持续补充)

    Specify Point(指定点)控件的获取 NX9+VS2012 #include <uf.h> #include <uf_ui.h> UF_initialize(); / ...

  8. docker核心技术(2)

    鸟瞰容器生态系统 一谈到容器,大家都会想到 Docker. Docker 现在几乎是容器的代名词.确实,是 Docker 将容器技术发扬光大.同时,大家也需要知道围绕 Docker 还有一个生态系统. ...

  9. 训练集(train set) 验证集(validation set) 测试集(test set)。

    训练集(train set) 验证集(validation set) 测试集(test set). http://blog.sina.com.cn/s/blog_4d2f6cf201000cjx.ht ...

  10. python 出现indentationError:expected an indented block!

    出现这个问题,代码一般是没问题的,剩下你要考虑: 1. 缩进对齐是否有问题 2. python脚本的格式是啥,如果你在linux上运行,编码需要是unix;  (大部分情况下,我们是在windows下 ...