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;
}

posted @ 2018-08-14 18:47  谜のNOIP  阅读(182)  评论(0编辑  收藏  举报