bzoj 1002: [FJOI2007]轮状病毒
\(\color{#0066ff}{ 题目描述 }\)
轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示
N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示
现给定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