bzoj 1002 [FJOI2007]轮状病毒 Matrix-Tree定理+递推

题面

题目传送门

解法

求无向图生成树个数,可以直接通过Matrix-Tree定理求

但是\(n≤100\),精度肯定爆了

所以先打个表找个规律:

\(1,5,16,45,121,320,841…\)

可以发现,奇数项感觉都是完全平方数,偶数项和完全平方数似乎也有点关系

仔细研究表,发现\(F_i=f_i^2-4((n+1)\%2)\),其中\(f_1=1,f_2=3,f_i=f_{i-2}+f_{i-1}\)

高精度一下即可

代码

#include <bits/stdc++.h>
#define N 110
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
string f[N], F[N];
string operator ^ (string x, string y) {
    int l1 = x.size() - 1, l2 = y.size() - 1;
    if (l1 > l2) swap(x, y), swap(l1, l2);
    for (int i = 1; i <= l2 - l1; i++) x = '0' + x;
    string ret = ""; int k = 0;
    for (int i = l2; ~i; i--) {
        int t = (x[i] - '0') + (y[i] - '0') + k;
        if (t > 9) t -= 10, k = 1; else k = 0;
        ret = (char)(t + '0') + ret;
    }
    if (k) ret = '1' + ret; return ret;
}
string operator - (string x, string y) {
    int l1 = x.size() - 1, l2 = y.size() - 1;
    for (int i = 1; i <= l1 - l2; i++) y = '0' + y;
    string ret = ""; int k = 0;
    for (int i = l1; i >= 0; i--) {
        int t = (x[i] - '0') - (y[i] - '0') - k;
        if (t < 0) t += 10, k = 1; else k = 0;
        ret = (char)(t + '0') + ret;
    }
    while (ret.size() > 1 && ret[0] == '0') ret.erase(ret.begin());
    return ret;
}
string operator * (string x, string y) {
    int l1 = x.size(), l2 = y.size();
    int a[210] = {0}, b[210] = {0}, c[410] = {0};
    for (int i = 0; i < l1; i++) a[l1 - i - 1] = x[i] - '0';
    for (int i = 0; i < l2; i++) b[l2 - i - 1] = y[i] - '0';
    for (int i = 0; i < l1; i++)
        for (int j = 0; j < l2; j++)
            c[i + j] += a[i] * b[j];
    for (int i = 0; i <= l1 + l2; i++)
        c[i + 1] += c[i] / 10, c[i] %= 10;
    string ret = "";
    for (int i = 0; i <= l1 + l2; i++) ret = (char)(c[i] + '0') + ret;
    while (ret.size() > 1 && ret[0] == '0') ret.erase(ret.begin());
    return ret;
}
int main() {
    int n; read(n);
    f[1] = "1", f[2] = "3";
    for (int i = 3; i <= n; i++) f[i] = f[i - 1] ^ f[i - 2];
    for (int i = 1; i <= n; i++) {
        F[i] = f[i] * f[i];
        if (i % 2 == 0) F[i] = F[i] - "4";
    }
    cout << F[n] << "\n";
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/copperoxide/p/9476702.html