BZOJ 1002: [FJOI2007]轮状病毒

BZOJ 1002: [FJOI2007]轮状病毒

Description

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

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

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

Input

  第一行有1个正整数n

Output

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

Sample Input

3

Sample Output

16

HINT

Source

Solution

先考虑成中心点到一条链上的方案数,f(x)表示链的成为x
显然把一条链拆成若干个区间,每个区间与中心点只连一条边
\(f(i)=\sum_{j=1}^ijf(i-j)\),\(f(0)=1\)
在考虑环的情况,\(g(i)\)为一个长为\(i\)的环的方案数,先考虑其中
一个点,枚举此点所在的区间长,那么这个区间有\(j\)种取法,那
这个区间就把还断成长度为\(i-j\)的链了
\(g(i)=\sum_{j=1}^ij^2f(i-j)\)
上方法复杂度为\(O(n^2)\),现在考虑优化。

使用做差的方法
\(F_{n-1}=1F_{n-2}+2F_{n-3}+...+(n-1)F_0\)
\(F_n=1F_{n-1}+2F_{n-2}+...+nF_{0}\)
推得
\(F_n=F_{n-1}+\sum_{k=0}^{n-1}F_k(n\geq1),F_0=F_1=1\)
计算一下前缀和,复杂度就成了\(O(n)\)
注意:需要高精度

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=next[i])
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const int MAX_N = 100;
struct Big {
	const static int w=5,base=1e9,lg=9;
	int x[w];
	Big(LL a=0) {*this = a;}
	Big operator=(LL a) {
		for(int i=0;i<w;i++,a/=base) x[i]=a%base;
		return *this;
	}
	Big operator+(const Big& b) const {
		Big c;
		for(int i=0,f=0;i<w;i++)
			if(f=(c.x[i]=x[i]+b.x[i]+f)>=base) c.x[i]-=base;
		return c;
	}
	Big operator+=(const Big& b) {return *this=*this + b;}
	Big operator*(const Big& b) const {
		Big c;LL t;
		fo(i,0,w-1) for (int j=0,f=0;i+j<w;j++) {
			t=(LL)b.x[i]*x[j]+c.x[i+j]+f;
			c.x[i+j]=t%base,f=t/base;
		}
		return c;
	}

	void print() const {
		int i = w-1;
		while(i &&!x[i]) --i;
		printf("%d", x[i--]);
		while(i >= 0) printf("%0*d",lg,x[i--]);
	}
};

int main() {
	int n=read();
	Big f(1),S(1),ans(n*(n-1));
	fo(i,1,n) {
		if(i>1) f=f+S;
		S+=f;
		if(i<=n-2) ans=ans+Big((n-i)*(n-i-1))*f;
	}
	(ans+f).print();
	return 0;
}
posted @ 2017-12-05 15:40  _patrick  阅读(149)  评论(0编辑  收藏  举报