BZOJ1002

来源:互联网 发布:淘宝商城-情侣装 编辑:程序博客网 时间:2024/06/05 23:01

传送门:BZOJ1002

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

我们需要以下知识:

Kirchhoff Matrix Tree定理:
G为无向图,取E为图G的度数矩阵,F为图G的邻接矩阵
称矩阵EF为图G的Kirchhoff矩阵R,任取与R同构的行列式R的任意一个n1阶主子式Q,其值为图G的生成树个数。

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

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

R=n111111310011131001030100111013n+1

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

Q=310001131000030000011100013n

将此行列式Laplace展开,可得

Q(n)=3×G(n1)2×G(n2)2

其中Q(n)QnG(n)指形如

310000131000030000011000013n

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

而将GLaplace展开可以发现有

G(n)=3×G(n1)G(n2)

详细过程就不写了。

于是有

ans=3×G(n1)2×G(n2)2

其中
G(n)=383×G(n1)G(n2)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();}
0 0