Description

  轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示:

  N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不
同的3轮状病毒,如下图所示:

  现给定n(N<=100),编程计算有多少个不同的n轮状病毒。

Input

  第一行有1个正整数n。

Output

  计算出的不同的n轮状病毒数输出。

Sample Input

3

Sample Output

16

这里是题目链接:[BZOJ]1002:轮状病毒

这里是题解:

方法一:打表找规律

先暴力求出一部分答案:

这里是暴力打表代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 110
using namespace std; struct abcd{
int to,next;
bool ban;
}table[M<<]; int head[M],tot=;
int n,ans; void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
} int fa[M],v[M],q[M],r,h; bool BFS()
{
int i;
r=h=;
memset(v,,sizeof v);
memset(fa,-,sizeof fa);
q[++r]=;
while(r!=h)
{
int x=q[++h];
for(i=head[x];i;i=table[i].next)
if(!table[i].ban)
{
if(table[i].to==fa[x])
continue;
if(v[table[i].to])
return ;
fa[table[i].to]=x;
v[table[i].to]=;
q[++r]=table[i].to;
}
}
if(r<=n)
return ;
return ;
} void DFS(int x)
{
if(x+x>tot)
{
if( BFS() )
++ans;
return ;
}
table[x<<].ban=table[x<<|].ban=;
DFS(x+);
table[x<<].ban=table[x<<|].ban=;
DFS(x+);
} int main()
{
int i;
for(int j=;j<=;j++){
memset(head,,sizeof head);
tot=;ans=;
n=j;
for(i=;i<=n;i++)
Add(,i),Add(i,),Add(i,i%n+),Add(i%n+,i);
DFS();
cout<<ans<<' ';
}printf("\n");
return ;
}

暴力打表

打出1-15的表(like this):

1     5      16     45      121

320   841     2205    5776     15125

39601  103680   271441   710645   1860496

Process exited after 48.06 seconds with return value 0

想将所有表打出来估计是不可能的事情,所以需要找规律。

这里是规律:

1 5 16 45 121 320 841 2205 5776 15125 39601 103680 271441 710645 1860496【1-15的答案】

第1、3、5、7...[奇数位]位是平方数 :

  1*1  4*4  11*11   29*29   76*76   199*199  521*521...

第2、4、6、8...[偶数位]位除以5后也是平方数:

  5*1*1  5*3*3  5*8*8  5*21*21  5*55*55   5*144*144 ...

【最美妙的事情发生了】:

奇数位:1  3  4  7  11  18  29  47  76...[粗体为原奇数位的算术平方根]

偶数位:1  2  3  5  8   13  21  34  55...[粗体为原偶数位除以5后的算术平方根]

(这个就属于改版的斐波拉契数列,只是初始值不一样)

然后求【改版斐波拉契数列】的值就行了。(但是要注意高精度!)

这里是推荐内容:

其实一般情况下还是很难看出来这个是改版斐波拉契数列的间隔值。

所以这里【倾情】推荐一个网站:Wolframalpha

这里输入之前打表的值:

然后这里就可以看见更多的值:

两三次【More】之后,基本上就有100个数了,然后就可以直接暴力打表。

【但是考场上不能用so sad :( 】

附:其实网上还流传了一种用这些打表出来的数:1 5 16 45 121 320 841 2205 5776 ……

得出了一个递推式:a[i]=a[i-1]*3-a[i-2]+2 ,用这个式子同样能够得出答案。

当然这个只是在[乱搞],找规律一般只使用于时间不够或者真的推不出来递推式的情况!

这里是找规律的代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct Num
{
int a[],len;
void Print()
{
for (int i=len-;i>=;i--)
printf("%d",a[i]);
printf("\n");
}
}a[],b[];
int n;
Num operator ^ (Num n,int b)
{
for (int i=;i<n.len;i++)
n.a[i]*=b;
for (int i=;i<n.len;i++)
{
n.a[i+]+=n.a[i]/;
n.a[i]%=;
}
while (n.a[n.len]!=)
{
n.a[n.len+]+=n.a[n.len]/;
n.a[n.len]%=;
n.len++;
}
return n;
}
Num operator * (Num a,Num b)
{
Num c;
c.len=a.len+b.len;
memset(c.a,,sizeof c.a);
for (int i=;i<a.len;i++)
for (int j=;j<b.len;j++)
c.a[i+j]+=a.a[i]*b.a[j];
for (int i=;i<c.len;i++)
{
c.a[i+]+=c.a[i]/;
c.a[i]%=;
}
while (c.a[c.len-]==) c.len--;
return c;
}
Num operator - (Num a,Num b)
{
for (int i=;i<b.len;i++)
a.a[i]-=b.a[i];
for (int i=;i<a.len;i++)
if (a.a[i]<)
{
a.a[i]+=;
a.a[i+]--;
}
while (a.a[a.len-]==) a.len--;
return a;
}
void eq(Num &a,Num b)
{
a.len=b.len;
for (int i=;i<a.len;i++) a.a[i]=b.a[i];
}
int main()
{
scanf("%d",&n);
a[].a[]=,a[].a[]=;
b[].a[]=,b[].a[]=;
a[].len=a[].len=b[].len=b[].len=;
for (int i=;i<=n;i++)
{
eq(a[i],(a[i-]^)-a[i-]);
eq(b[i],(b[i-]^)-b[i-]);
}
Num ans;
if (n%==) eq(ans,a[(n+)/]*a[(n+)/]);
else eq(ans,b[n/]*b[n/]^);
ans.Print();
return ;
}

【BZOJ】1002:轮状病毒

方法二:【基尔霍夫矩阵】

这里是预备知识:

这个题是求两两之间只有一条直接或间接路径(没有环,形成一棵树)的方案数。

一个专有名词叫做:【生成树计数】

生成树计数:通常情况是由Kirchhoff's Matrix-Tree Theorem(基尔霍夫矩阵矩阵树定理)求解。

基尔霍夫矩阵:也叫导纳矩阵、拉普拉斯矩阵或离散拉普拉斯算子。

给定一个有n个顶点的图G,它的拉普拉斯矩阵 定义为:  L=D-A 

其中:D矩阵叫做【度矩阵】;A矩阵叫做【邻接矩阵】

什么是度矩阵?

对于这种【无向图】,每一个点的度就是它连边的个数

【for example】:4的度数就是3(和3,5,6连边)

用这些度构成度矩阵

仅当矩阵中【 i==j 】时D[i][j]才有值:此时D[i][j] = i 号点的度数

如果【 i!=j 】,D[i][j]就赋值为0.

所以上面这个图的度矩阵为:

什么是邻接矩阵?

当 i 号点和 j 号点有连边的时候,将A[i][j]=1,A[j][i]=1;(双向边)

其余 i、j 没有连边的 A[i][j]=0;

【当 i==j 时,A[i][j]=0 】

例子的邻接矩阵为:

所以基尔霍夫矩阵【 L=D-A 】为:

现在已经求得基尔霍夫矩阵,那么

Kirchhoff's Matrix-Tree Theorem(基尔霍夫矩阵矩阵树定理)又是什么呢?

基尔霍夫矩阵C的任意余子式Mij,Mij的行列式的值就是图G的生成树个数。

这里是大神博客:生成树计数问题——矩阵树定理及其证明

(证明见这位大神博客,蒟蒻表示不会证明这个,只会用ORZ

什么是余子式?

简单来说就是:一个行列式的余子式Mij就是去掉aij所在的行和列。

M23的余子式就是:

(这里第三行删掉了,第三列也删掉了)

这里是本题真正的题解:

首先,根据以上条件,对于该图构造基尔霍夫矩阵

(删除中心原点的行和列,设n为圈上的点的个数)

对角线aij表示与该点相连的个数。

如果i点和j点有连边,那么aij就赋值为-1.

(对于第一排和最后一排,因为这个图是一个圆圈,所以n与1相连)

然后计算出这个行列式的值就是本题的答案了,将该答案设为g[n]

这里是计算过程:

方法①:高斯消元 O(n^3) 大概可以过吧,没写过ORZ。

方法②:利用行列式的性质推导。

这里有一张大图,是推导全过程,结合此图浏览下列题解能更方便理解

建议保存本图,然后用画图工具打开,边看图,边理解博客。

预备知识:(建议先了解行列式的各种性质)

对于本题,这里主要用两个性质

1.n阶行列式,按行列展开。

展开方法:行列式等于它的任意一行(列)的各元素与其对应的代数余子式乘积之和。

即:

代数余子式的计算方法:对于一个4阶行列式的余子式M23.

代数余子式A23=M23*(-1)^(2+3)=-M23

所以公式为:Aij=Mij*(-1)^(i+j)

2.三角行列式的计算:主对角线以上的部分全为0。

注:建议先熟悉行列式的各种性质

现在,将本题的行列式按最后一行展开。

最后一行第一项展开为:(为了之后方便,将其设为①号式子[n-1阶行列式])

最后一行倒数第二项展开为:(为了之后方便,将其设为②号式子[n-1阶行列式])

最后一行最后一项展开为:(为了之后方便,将其设为③号式子[n-1阶行列式])

因为③号式子形式特别,现将对角线为3,然后两边为-1的式子设为f[i]

所以③号式子设为f[n-1].(注意这里和之前的基尔霍夫矩阵不一样,因为这里a1n、an1不再为-1)

原式=①号+②号+③号

对于①号式子:按第一行展开。

①号式子第一项展开得到下列式子[n-2阶式子]:

明显运用之前提到的性质2,可以求出,该式子的值为:(-1)^(n-1)

①号式子最后一项得到下列式子[n-2阶式子]:

明显这个矩阵就像f函数的矩阵形式

所以①号式子的值可以表示为:-1-f[n-2]

对于②号式子:按最后一列展开。(注意是列)

②号式子按最后一列第一项展开得到下列式子[n-2阶式子]:

根据三角行列式计算方法,得到该行列式的值为:-1

②号式子按照最后一项展开得到下列式子[n-2阶式子]:

明显形式又是相同的,所以该行列式的值可以表示为:-f[n-2]

所以②号式子的值为:-f[n-2]-1

而对于③号式子:

本身形式相同,所以表示为:3*f[n-1]

综上g[n]=①+②+③=-1-f[n-2]-f[n-2]-1+3*f[n-1]=3*f[n-1]-2*f[n-2]-2

现在就要求出f函数之间的关系

对于无系数的③号式子:按照最后一行展开。

倒数第二项展开为:(为了之后方便,将其设为④号式子[n-2]阶行列式])

最后一项展开为:([n-2]阶行列式)

明显这个形式就是之前的f函数,所以可以表示为:3*f[n-2].

对于④号式子:按照最后一行展开。

倒数第二项展开:

因为这个行列式中有一列为0,按照行列式的定义,它的值为0.

最后一项展开:([n-3]阶行列式)

这个行列式的值就可以表示为:-f[n-3].

所以④号式子的值为:-f[n-3].

根据③号式子、④号式子:可以得出f[n-1]=3*f[n-2]-f[n-3]

现在有两个式子:

g[n]=3*f[n-1]-2*f[n-2]-2

f[n]=3*f[n-1]-f[n-2]

如何将它化成一个只有g函数的递推式:

首先g函数f函数的关系式为g[i]=3*f[i-1]-2*f[i-2]-2

因为3*f[i-1]=9*f[i-2]-3*f[i-3]

  3*g[i-1]=9*f[i-2]-6*f[i-3]-6

所以(用g[i-1]来替代f[i-1])

g[i]=3*g[i-1]+3*f[i-3]+6-2*f[i-2]-2

    =3*g[i-1]+3*f[i-3]-2*f[i-2]+4

又因为-2*f[i-2]=-6*f[i-3]+2*f[i-4]

所以(将g[i]中的f[i-2]展开)

g[i]=3*g[i-1]+3*f[i-3]-6*f[i-3]+2*f[i-4]+4

    =3*g[i-1]-3*f[i-3]+2*f[i-4]+4

又因为:-g[i-2]=-3*f[i-3]+2*f[i-4]-2

所以:g[i]=3*g[i-1]-g[i-2]+2

g函数的初值:

g[1]=1、g[2]=5

这里是最终代码(注意高精度!):

#include<iostream>
#include<cstdio>
using namespace std;
struct data{
int a[],len;
};
int n;
data mul(data a,int k)
{
for(int i=;i<=a.len;i++)
a.a[i]*=k;
for(int i=;i<=a.len;i++)
{
a.a[i+]+=a.a[i]/;
a.a[i]%=;
}
if(a.a[a.len+]!=)a.len++;
return a;
}
data sub(data a,data b)
{
a.a[]+=;
int j=;
while(a.a[j]>=){a.a[j]%=;a.a[j+]++;j++;}
for(int i=;i<=a.len;i++)
{
a.a[i]-=b.a[i];
if(a.a[i]<){a.a[i]+=;a.a[i+]--;}
}
while(a.a[a.len]==)a.len--;
return a;
}
int main()
{
data f[];f[].a[]=;f[].a[]=;
f[].len=f[].len=;
scanf("%d",&n);
for(int i=;i<=n;i++)
f[i]=sub(mul(f[i-],),f[i-]);
for(int i=f[n].len;i>;i--)
printf("%d",f[n].a[i]);
return ;
}

【BZOJ】1002:轮状病毒

这里还有一种大犇的证明1002: [FJOI2007]轮状病毒 (值得一看orz)

梦想总是要有的,万一实现了呢?

【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)的更多相关文章

  1. BZOJ 1002 - 轮状病毒 - [基尔霍夫矩阵(待补)+高精度]

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1002 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生 ...

  2. bzoj1002: [FJOI2007]轮状病毒(基尔霍夫矩阵)

    1002: [FJOI2007]轮状病毒 题目:传送门 题解: 决定开始板刷的第一题... 看到这题的时候想:这不就是求有多少种最小生成树的方式吗? 不会啊!!!%题解... 什么鬼?基尔霍夫矩阵?? ...

  3. [bzoj1002] [FJOI2007]轮状病毒轮状病毒(基尔霍夫矩阵)

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子 和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下 ...

  4. BZOJ 1002: [FJOI2007]轮状病毒【生成树的计数与基尔霍夫矩阵简单讲解+高精度】

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

  5. bzoj 1002 [FJOI2007]轮状病毒 高精度&&找规律&&基尔霍夫矩阵

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

  6. bzoj 1002 找规律(基尔霍夫矩阵)

    网上说的是什么基尔霍夫矩阵,没学过这个,打个表找下规律,发现 w[i]=3*w[i-1]-w[i-2]+2; 然后写个高精直接递推就行了 //By BLADEVIL var n :longint; a ...

  7. BZOJ1002 FJOI2007 轮状病毒 【基尔霍夫矩阵+高精度】

    BZOJ1002 FJOI2007 轮状病毒 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原 ...

  8. BZOJ 4031 HEOI2015 小Z的房间 基尔霍夫矩阵+行列式+高斯消元 (附带行列式小结)

    原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4031 Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可 ...

  9. bzoj1002 轮状病毒 暴力打标找规律/基尔霍夫矩阵+高斯消元

    基本思路: 1.先观察规律,写写画画未果 2.写程序暴力打表找规律,找出规律 1-15的答案:1    5    16    45    121 320 841     2205   5776 151 ...

随机推荐

  1. 注冊成为Windows Phone开发人员而且解锁Windows Phone 8.1手机

    注冊成为Windows Phone开发人员而且解锁Windows Phone 8.1手机 上篇文章介绍了怎样使用Qt Creator和Visual Studio构建Windows Phone 8.1应 ...

  2. 【MongoDB】MongoDB的下载 安装 配置及使用

    windows系统  教程 1.下载地址   (官方提供根据系统位数选择对应的bit.exe下载) 由于自己win32系统不支持该官方版本,在网上又找了个 mongodb-win32-i386版本 p ...

  3. [Baltic2013]ballmachine BZOJ3133

    分析: 我们考虑,因为每次放置的时候,都是向子树中含有的编号最小的哪一个走,那么放置的顺序是固定的,我们将边以to的子树最小排序,之后得到的出栈序就是球的放入顺序.目测可以使用堆来实现,线段树也能实现 ...

  4. 20155306 白皎 《网络攻防》 EXP7 网络欺诈技术防范

    20155306 白皎 <网络攻防> EXP7 网络欺诈技术防范 问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 局域网内的攻击以及连接公众场所的共享wifi (2)在日常 ...

  5. linux下通过软连接实现访问项目路径外面的资源

            在javaweb项目开发中,图片上传是个比较常见的场景.一般都是在项目路径下建个文件夹,然后上传到该文件夹下:这样这个图片就可以和静态资源一样被直接访问.这样的好处就是访问这图片特别方 ...

  6. OFS环境,删除Resource 时出现错误失败,应该如何继续

    From the Windows failover cluster manager,select the group listener, stop it, and delete it.  Do the ...

  7. system表空间不可改名

    SQL> startup mount;ORACLE instance started. Total System Global Area  814227456 bytesFixed Size   ...

  8. [CF917D]Stranger Trees[矩阵树定理+解线性方程组]

    题意 给你 \(n\) 个点的无向完全图,指定一棵树 \(S\),问有多少棵生成树和这棵树的公共边数量为 \(k\in[0,n-1]\) \(n\leq 100\) 分析 考虑矩阵树定理,把对应的树边 ...

  9. Reflux系列01:异步操作经验小结

    写在前面 在实际项目中,应用往往充斥着大量的异步操作,如ajax请求,定时器等.一旦应用涉及异步操作,代码便会变得复杂起来.在flux体系中,让人困惑的往往有几点: 异步操作应该在actions还是s ...

  10. 使用Windows Server 2003搭建一个asp+access网站

    鼠标右键->新建->网站->下一步->描述(随便给一个,这里我以test为例) ->下一步->下一步->输入主目录的路径,默认路径下是C:\Inetpub\w ...