• 【HDU5730】Shell Necklace-CDQ分治+FFT(分治FFT)


    测试地址:Shell Necklace
    题目大意:一串链形贝壳项链(不是环形),有ai种方案装饰连续i个贝壳,问装饰整串项链有多少种方案。
    做法:本题需要用到CDQ分治+FFT(分治FFT)。
    首先令f(i)为装饰长为i的项链的方案数,特殊地,令f(0)=1,那么我们很快能得出状态转移方程:
    f(i)=j=1if(ij)aj
    直接计算这个方程是O(n2)的,不能接受。注意到等号右边的部分是一个卷积形式的式子,但是这个卷积和往常普通FFT可以做的卷积不同,它涉及到f自己和另一个数组的卷积,所以我们不能用普通的FFT来解决问题。
    这时候分治FFT就出场了。分治FFT也可以写成CDQ分治+FFT。我们知道CDQ分治的主要思想就是对于每个区间[l,r],先递归计算区间[l,mid]中的答案,然后计算[l,mid][mid+1,r]中答案的贡献,最后递归计算区间[mid+1,r]。这里我们采用类似的过程,先算出区间[l,mid]中所有的f,然后将这一段fa做卷积,求出它们对区间[mid+1,r]中所有f的贡献,用FFT即可,最后计算区间[mid+1,r]。根据主定理,这个算法的时间复杂度是O(nlog2n)的,可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=313;
    const double pi=acos(-1.0);
    int n,rev[400010];
    ll A[100010],f[100010];
    struct Complex
    {
        double x,y;
    }a[400010],b[400010];
    Complex operator + (Complex a,Complex b) {Complex s={a.x+b.x,a.y+b.y};return s;}
    Complex operator - (Complex a,Complex b) {Complex s={a.x-b.x,a.y-b.y};return s;}
    Complex operator * (Complex a,Complex b) {Complex s={a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};return s;}
    
    void FFT(Complex *a,int type,int n)
    {
        for(int i=0;i<n;i++)
            if (i<rev[i]) swap(a[i],a[rev[i]]);
        for(int mid=1;mid<n;mid<<=1)
        {
            Complex W={cos(pi/mid),type*sin(pi/mid)};
            for(int l=0;l<n;l+=(mid<<1))
            {
                Complex w={1.0,0.0};
                for(int k=0;k<mid;k++,w=w*W)
                {
                    Complex x=a[l+k],y=w*a[l+mid+k];
                    a[l+k]=x+y;
                    a[l+mid+k]=x-y;
                }
            }
        }
        if (type==-1)
        {
            for(int i=0;i<n;i++)
                a[i].x/=(double)n;
        }
    }
    
    void solve(int l,int r)
    {
        if (l==r) return;
        int mid=(l+r)>>1;
    
        solve(l,mid);
    
        int bit=0,x=1;
        while(x<((r-l+1)<<1)) x<<=1,bit++;
        for(int i=0;i<x;i++)
            a[i].x=a[i].y=b[i].x=b[i].y=0.0;
        for(int i=0;i<mid-l+1;i++)
            a[i].x=f[l+i];
        for(int i=0;i<r-l;i++)
            b[i].x=A[i+1];
        rev[0]=0;
        for(int i=1;i<x;i++)
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        FFT(a,1,x),FFT(b,1,x);
        for(int i=0;i<x;i++)
            a[i]=a[i]*b[i];
        FFT(a,-1,x);
    
        for(int i=mid+1;i<=r;i++)
        {
            f[i]+=a[i-l-1].x+0.5;
            f[i]%=mod;
        }
    
        solve(mid+1,r);
    }
    
    int main()
    {
        while(scanf("%d",&n)&&n)
        {
            memset(f,0,sizeof(f));
            f[0]=1;A[0]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&A[i]);
                A[i]%=mod;
            }
            solve(0,n);
            printf("%lld
    ",f[n]);
        }
    
        return 0;
    }
  • 相关阅读:
    “图灵&博客园&互动网有奖书评征集活动——微软技术系列”评选结果
    像优秀的SQL程序员一样思考
    倚天·屠龙——唯我独尊
    CSS与HTML设计模式全集(350余种)
    游览器兼容冲突的常见css
    嵌入多媒体文本
    删除确认代码
    用!important解决IE和Mozilla的布局差别
    四大游览器兼容问题综合实例
    jQuery事件之鼠标事件
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793475.html
Copyright © 2020-2023  润新知