码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1002: [FJOI2007]轮状病毒

时间:2017-12-05 16:01:33      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:-o   i++   ret   const   计算   alt   图片   desc   img   

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

BZOJ 1002: [FJOI2007]轮状病毒

标签:-o   i++   ret   const   计算   alt   图片   desc   img   

原文地址:http://www.cnblogs.com/patricksu/p/7987292.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!