\(\color{#0066ff}{ 题目描述 }\)

轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示

bzoj 1002: [FJOI2007]轮状病毒_干货

 N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示

bzoj 1002: [FJOI2007]轮状病毒_干货_02

现给定n(N<=100),编程计算有多少个不同的n轮状病毒

\(\color{#0066ff}{输入格式}\)

第一行有1个正整数n

\(\color{#0066ff}{输出格式}\)

计算出的不同的n轮状病毒数输出

\(\color{#0066ff}{输入样例}\)

3

\(\color{#0066ff}{输出样例}\)

16

\(\color{#0066ff}{数据范围与提示}\)

none

\(\color{#0066ff}{ 题解 }\)

暴力\(2^n\)

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
struct node {
    int x, y;
    node(int x = 0, int y = 0): x(x), y(y) {}
}e[110000];
int b[100000];
int n, m, ans;
int fa[1000010];
int findset(int x) { return x == fa[x]? fa[x] : fa[x] = findset(fa[x]); }
void getans(int num) {
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1; i <= num; i++) {
        int x = findset(e[b[i]].x);
        int y = findset(e[b[i]].y);
        if(x == y) return;
        fa[x] = y;
    }
    ans++;
}

void dfs(int dep, int num) {
    if(dep == m + 1) {
        if(num != n - 1) return;
        getans(num);
        return;
    }
    b[num + 1] = dep;
    dfs(dep + 1, num + 1);
    dfs(dep + 1, num);
}
int main() {
    n = in() + 1;
    for(int i = 2; i <= n; i++) e[++m] = node(1, i);
    for(int i = 2; i < n; i++) e[++m] = node(i, i + 1);
    if(n > 3) e[++m] = node(n, 2);
    dfs(1, 0);
    printf("%d", ans);
    return 0;
}

打表

1, 5, 16, 45, 121, 320, 841, 2205, 5776, 15125, 39601, 103680, 271441 

然后发现有很多完全平方数

发现都在奇数项位置

于是开方后得到

1, 4, 11, 29, 76,199, 521

通过下面的程序找到规律

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
int f[] = {1, 4, 11, 29, 76, 199, 521};
bool judge(int i, int j, int v) {
	for(int g = 3; g <= 6; g += 2)
		if(i * f[g - 2] + j * f[g - 1] + v != f[g]) return false;
	return true;
}
int main() {
	for(int i = -10; i <= 10; i++)
		for(int j = -10; j <= 10; j++)
			for(int v = -10; v <= 10; v++) {
				if(judge(i, j, v)) {
					printf("%d * f[i - 2] + %d * f[i - 1] + %d\n" , i, j, v);
				}
			}
	return 0;
}

发现规律 \(f[i]=3*f[i-1]-f[i-2]\)

讨论完奇数项,自然到了偶数项,发现都是5的倍数,除去5之后,居然跟奇数项的规律一毛一样

还得写高精qwq

Code

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
struct node {
	int a[1050], len;
	node(int x = 0) {
		memset(a, 0, sizeof a);
		if(!x) len = 1;
		else len = 0;
		while(x) {
			a[++len] = x % 10;
			x /= 10;
		}
	}
	void jinwei() { while(len > 1 && a[len] == 0) len--; }
	friend node operator + (const node &a, const node &b) {
		node t(0);
		t.len = std::max(a.len, b.len) + 3;
		for(int i = 1; i <= t.len; i++) {
			t.a[i] += a.a[i] + b.a[i];
			t.a[i + 1] += t.a[i] / 10;
			t.a[i] %= 10;
		}
		return t.jinwei(), t;
	}
	friend node operator - (const node &a, const node &b) {
		node t = a;
		for(int i = 1; i <= t.len; i++) {
			t.a[i] -= b.a[i];
			if(t.a[i] < 0) t.a[i] += 10, t.a[i + 1]--;
		}
		return t.jinwei(), t;
	}
	friend node operator * (const node &a, const node &b) {
		node t(0);
		t.len = a.len + b.len + 2;
		for(int i = 1; i <= a.len; i++)
			for(int j = 1; j <= b.len; j++) {
				t.a[i + j - 1] += a.a[i] * b.a[j];
				t.a[i + j] += t.a[i + j - 1] / 10;
				t.a[i + j - 1] %= 10;
			}
		return t.jinwei(), t;
	}
	void print() {
		for(int i = len; i >= 1; i--) putchar(a[i] + '0');
		puts("");
	}
}A[111];
int main() {
	int n = in();
	node tre(3);
	if(n & 1) {
		A[1] = node(1);
		A[3] = node(4);
		for(int i = 5; i <= n; i += 2) A[i] = tre * A[i - 2] - A[i - 4];
		(A[n] * A[n]).print();
	}
	else {
		if(n == 2) printf("%d", 5);
		else {
			A[4] = node(3);
			A[6] = node(8);i
			for(int i = 8; i <= n; i += 2) A[i] = tre * A[i - 2] - A[i - 4];
			(A[n] * A[n] * node(5)).print();
		}
	}
	return 0;
}
----olinr