BZOJ1002

传送门:BZOJ1002

似乎做法挺多,不过我并不懂得基于连通性的动态规划,于是只能做纯数学解法。

我们需要以下知识:

Kirchhoff Matrix Tree定理:

设G为无向图,取E为图G的度数矩阵,F为图G的邻接矩阵

称矩阵E?F为图G的Kirchhoff矩阵R,任取与R同构的行列式R′的任意一个n?1阶主子式Q,其值为图G的生成树个数。

这个定理不是显然的,但我们在这里不证,因为它与本题的讨论无关。

取中心点为0号点,其余点按顺时针顺序标为1234…n,则有

R=??????????????n?1?1?1?1?1?13?100?1?1?13?100?10?3?0?100???1?1?10??13??????????????n+1

这里我们显然会取1-n行主子式,故

Q=∣∣∣∣∣∣∣∣∣∣∣∣3?1000?1?13?10000?3?00…0???00…??1??1?1000?13∣∣∣∣∣∣∣∣∣∣∣∣n

将此行列式Laplace展开,可得

Q(n)=3×G(n?1)?2×G(n?2)?2

其中Q(n)指形如Q的n阶行列式的值,G(n)指形如

∣∣∣∣∣∣∣∣∣∣∣∣3?10000?13?10000?3?00…0???00…??1??10000?13∣∣∣∣∣∣∣∣∣∣∣∣n

的带状行列式的值。这个式子的证明详细步骤就不写了。

而将GLaplace展开可以发现有

G(n)=3×G(n?1)?G(n?2)

详细过程就不写了。

于是有

ans=3×G(n?1)?2×G(n?2)?2

其中

G(n)=?????383×G(n?1)?G(n?2)n=1n=2otherwise

然后高精度就可以AC了。

【吐槽:题解LaTeX代码写的时间比我做题时间还长】

代码上的小细节见下。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

struct node
{
    int a[1100],l;
    node()
    {
        memset(a,0,sizeof(a));
        l = 1;
    }
    friend inline node operator *(int x,node &y)
    {
        node ret; ret.l = y.l+1;
        for (int i = 1;i <= y.l;++i)
        {
            ret.a[i] += y.a[i]*x;
            ret.a[i+1] += ret.a[i]/10;
            ret.a[i] %= 10;
        }
        if (ret.a[ret.l] == 0) ret.l--;
        return ret;
    }
    friend inline node operator -(node x,node y)
    {
        node z; z.l = max(x.l,y.l);
        for (int i = 1;i <= z.l;++i)
        {
            z.a[i] = x.a[i]-y.a[i];
            while (z.a[i] < 0)
                z.a[i] += 10,x.a[i+1]--;
        }
        while (z.l > 1&&z.a[z.l] == 0)z.l--;
        return z;
    }
    friend inline node operator +(node &x,int y)
    {
        node ret = x;
        ret.a[1] += y;
        for (int i = 1;i <= ret.l;++i)
        {
            if (ret.a[i] >= 10)
                ret.a[i]-=10,ret.a[i+1]++;
            else break;
        }
        if (ret.a[ret.l+1]) ret.l++;
        return ret;
    }
    inline void print()
    {
        for (int i = l;i >= 1;--i)
            printf("%d",this->a[i]);
    }
};

int n;
node g[110];
node ans;

void Readdata()
{
    freopen("loli.in","r",stdin);
    scanf("%d",&n);
}

void Solve()
{
    g[1]=g[1]+3;
    g[2]=g[2]+8;
    if(n<=2){
        g[n].print();
        return;
    }
    for(int i=3;i<=n;i++)
        g[i]=3*g[i-1]-g[i-2];
    ans=3*g[n-1]-2*g[n-2];
    ans=ans+(-2);
    ans.print();
}

void Close()
{
    fclose(stdin);
    fclose(stdout);
}

int main()

{
    Readdata();
    Solve();
    Close();
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 02:44:43

BZOJ1002的相关文章

bzoj1002[FJOI2007]轮状病毒

bzoj1002[FJOI2007]轮状病毒 题意: N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n,计算有多少个不同的n轮状病毒.N<=100 题解: 公式:f[i]=f[i-1]*3-f[i-2]+2,i≥3,f[1]=1,f[2]=5.(我承认我是抄的QAQ因为我根本不懂什么矩阵树定理~ 又是高精度,又被我用python水掉了…… 代码: 1 n=int(raw_input()) 2 a=1 3 b=

[BZOJ1002] [FJOI2007] 轮状病毒 (基尔霍夫矩阵)

Description 给定n(N<=100),编程计算有多少个不同的n轮状病毒. Input 第一行有1个正整数n. Output 将编程计算出的不同的n轮状病毒数输出 Sample Input 3 Sample Output 16 HINT Source Solution 基尔霍夫矩阵,左转生成树的计数及其应用 推出本题的递推式:f[n] = f[n - 1] * 3 - f[n - 2] + 2 如果你能看懂,拜托给我讲讲,本人不懂. 注意要使用高精度 1 #include <cstri

[bzoj1002][FJOI2007]轮状病毒-题解[基尔霍夫矩阵][高精度][递推]

Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图所示 N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n(N<=100),编程计算有多少个不同的n轮状病毒 Input 第一行有1个正整数n Output 计算出的不同的n轮状病毒数输出 Sample Input

[bzoj1002][FJOI2007 轮状病毒] (生成树计数+递推+高精度)

Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图所示 N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n(N<=100),编程计算有多少个不同的n轮状病毒 Input 第一行有1个正整数n Output 计算出的不同的n轮状病毒数输出 Sample Input

bzoj1002轮状病毒

这题正解基尔霍夫矩阵(本蒟蒻不会) 于是就找规律吧. 前7项答案为 1 5 16 45 121 320 841 其实可以看成 1*1  3*3-4  4*4  7*7-4  11*11  18*18-4  29*29 4=3+1,7=4+3,11=7+4... 就是一个Fibonacci 第一项为1,第二项为3 F[n]=f(n)^2-4*(1-n%2); 再加个高精度就完了. (Ps:懒得打高精度减了,直接减了4) 1 #include <cstdio> 2 #include <cst

bzoj1002 生成树计数 找规律

这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它不出现分数.但过程中会出现负数,高精度处理负数太麻烦. 用Python打表?好吧,Python还不熟,写不出来..... 所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分. 最终只能求助于题解了... 好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=

BZOJ1002 FJOI2007 轮状病毒 递推

题意:给定一个轮状结构(中间一个点,周围有N个点以环状围住这个点),从不相交的2*N-1条边中选N条边,使任意两点间有且只有一条联通路径. 题解:请点这里.然而如果考场上考到直接打表找规律好了 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int

bzoj1002题解

[题意分析] 给你一张特殊的,被称为"轮状基"的无向图,求其生成树个数. [解题思路] 引理: 基尔霍夫矩阵: 基尔霍夫矩阵=度数矩阵-邻接矩阵(邻接矩阵权=两点连边数) Matrix-Tree定理: 对于任意一个无向图,其生成树个数为其基尔霍夫矩阵的任意一个余子式的行列式值. 算法一: 直接暴力构图,用Matrix-Tree定理算出生成树个数,复杂度O(n^3),理论可过,但考虑到高精度.. 附上一个算矩阵行列式的小公举工具. 算法二: 听说这个图很特殊,那一定有一些特殊性质? 先写

值得一做》关于数学与递推 BZOJ1002 (BZOJ第一页计划)(normal+)

什么都不说先甩题目 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图所示 N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n(N<=100),编程计算有多少个不同的n轮状病毒   Input 第一行有1个正整数n Output 计算出的不同的n轮状病毒数输出 S