代码改变世界

1002: [FJOI2007]轮状病毒

2019-12-10 21:30  一只弱鸡丶  阅读(144)  评论(0编辑  收藏  举报

题目链接:

题意:就是给出n,表示有n+1个点通过n条边相连。求一共有多少种连法!总的来说就是求生成树的个数有多少种

这是一篇大佬的题解:

其实说了一大堆就是证明了f[i]=3f[i-1]-f[i-2]+2。这个就是本题的递推式

而这个怎么来的?大佬的证明说明了一个基尔霍夫矩阵的任一余子式的行列式的值就是该图的生成树的个数 

所以我们就可以通过对余子式做代数余子式的展开求行列式的方法,就可以推出上面那个公式,不会推就记住好了(反正我觉得我就算现在会推过几天就忘了emmm)

本题虽然最大数据只有100,但是还是顶不住爆ll,所以要写个高精度加法跟减法,那个乘法相当于加三次(我不想敲高精度乘法,主要是不太会)

#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <iostream>
#include <functional>
using namespace std;
#define ll long long
#define fi first
#define se second
#define re register
#define pb push_back
void read(int &a)
{
    a=0;
    int d=1;
    char ch;
    while(ch=getchar(),ch>'9'||ch<'0')
        if(ch=='-')
            d=-1;
    a=ch-'0';
    while(ch=getchar(),ch>='0'&&ch<='9')
        a=a*10+ch-'0';
    a*=d;
}
void write(int x)
{
    if(x<0)
        putchar(45),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
string f[105];
string add(string st1,string st2)
{
    string str;
    int d=0;
    int len1=st1.length();
    int len2=st2.length();
    if(len1>len2)
        for(re int i=0;i<len1-len2;i++)
            st2='0'+st2;
    else
        for(re int i=0;i<len2-len1;i++)
            st1='0'+st1;
    for(re int i=st1.size()-1;i>=0;i--)
    {
        int a,b;
        a=st1[i]-'0';
        b=st2[i]-'0';
        a=a+b+d;
        d=a/10;
        str=char(a%10+'0')+str;
    }
    if(d!=0)  str=char(d+'0')+str;
    return str;
}
string solve(int x)
{
    string s="";
    do
    {
        s.pb(x%10);
        x/=10;
    }while(x);
    reverse(s.begin(),s.end());
    return s;
}
string sub(string st1,string st2)
{
    string tem;
    int d=0;
    bool f=true;
    int len1=st1.length();
    int len2=st2.length();
    if(len1<len2||(len1==len2&&st1<st2))
    {
        string t=st1;
        st1=st2;
        st2=t;
        int tt=len1;
        len1=len2;
        len2=tt;
        f=false;
    }
    else if(len1==len2&&st1==st2)
    {
        tem='0';
        return tem;
    }
    for(re int i=1;i<=len1-len2;i++)
        st2='0'+st2;
    for(re int i=len1-1;i>=0;i--)
    {
        int t=(st1[i]-'0')-(st2[i]-'0')-d;
        if(t<0)
        {
            t+=10;
            d=1;
        }
        else
            d=0;
        tem=char(t+'0')+tem;
    }
    if(tem.size()==1)
    {
        if(!f)
            tem='-'+tem;
        return tem;
    }
    while(1)
    {
        if(tem[0]=='0')
            tem.erase(0,1);
        else
            break;
    }
    if(!f)
        tem='-'+tem;
    return tem;
}
int main()
{
    int n;read(n);
    string st1,st2;
    f[1]="1",f[2]="5";
    st1=solve(n);st2=solve((n+1)*n);
    for(re int i=3;i<=n;i++)
    {
        for(re int j=1;j<=3;j++) f[i]=add(f[i],f[i-1]);
        f[i]=add(f[i],"2");
        f[i]=sub(f[i],f[i-2]);
    }
    cout<<f[n]<<endl;
    return 0;
}