• 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(ngeq1),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;
    }
    
  • 相关阅读:
    js 简单getByClass得封装
    微信红包的随机算法
    js 淘宝评分
    HDU 1023 Train Problem II( 大数卡特兰 )
    HDU 1576 A/B( 逆元水 )
    HDU 5533 Dancing Stars on Me( 有趣的计算几何 )
    POJ 1664 放苹果( 递推关系 )
    HDU 2095 find your present (2)( 位运算 )
    POJ 3517 And Then There Was One( 约瑟夫环模板 )
    POJ 1988 Cube Stacking( 带权并查集 )*
  • 原文地址:https://www.cnblogs.com/patricksu/p/7987292.html
Copyright © 2020-2023  润新知