zoukankan      html  css  js  c++  java
  • 【HDU5730】 Shell Necklace

    HDU5730 Shell Necklace


    题目大意

    已知连续i(1<=i<=n)个贝壳组合成一段项链的方案数a[i],求组合成包含n个贝壳的项链的总方案数。

    Solution

    1. cdq分治

    我们考虑最朴素的(dp​).

    (f_i​)表示包含(i​)个贝壳的方案数,很容易写出转移方程:

    (f_i=sum_{j=1}^if_{i-j}×a_j)

    发现这个dp方程直接转移是(O(n^2))的,要优化一下....

    这个式子不就是分治FFT的式子?

    直接cdq不就好了吗?

    1. 多项式求逆

    考虑这个东西怎么求逆对吧.

    生成函数构出来直接就可以求式子了...(坑+1)

    代码实现

    分治FFT

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=1000010,Mod=313;
    const double Pi=acos(-1.0);
    int a[N],dp[N],n;
    struct node
    {
    	double x,y;
    	node operator+(const node b)const{return (node){x+b.x,y+b.y};}
    	node operator-(const node b)const{return (node){x-b.x,y-b.y};}
    	node operator*(const node b)const{return (node){x*b.x-y*b.y,x*b.y+y*b.x};}
    }A[N],B[N];
    int r[N],limit;
    void FFT(node *A,int type)
    {
    	for(int i=0;i<limit;i++)
    		if(i<r[i])swap(A[i],A[r[i]]);
    	for(int mid=1;mid<limit;mid<<=1)
    	{
    		node Root=(node){cos(Pi/mid),type*sin(Pi/mid)};
    		for(int R=mid<<1,j=0;j<limit;j+=R)
    		{
    			node Mi=(node){1,0};
    			for(int k=0;k<mid;k++,Mi=Mi*Root)
    			{
    				node X=A[j+k],Y=Mi*A[j+mid+k];
    				A[j+k]=X+Y;
    				A[j+mid+k]=X-Y;
    			}
    		}
    	}
    }
    void cdq(int l,int R)
    {
    	if(l==R)
    	{
    		dp[l]=(dp[l]+a[l])%Mod;
    		return;
    	}
    	int mid=(l+R)>>1;
    	cdq(l,mid);
    	limit=1;int L=0,len=R-l+1;
    	while(limit<=len)limit<<=1,L++;
    	for(int i=0;i<limit;i++)
    		r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
    	for(int i=0;i<limit;i++)A[i].x=B[i].x=0,A[i].y=B[i].y=0;
    	for(int i=l;i<=mid;i++)A[i-l].x=dp[i],A[i].y=0;
    	for(int j=1;j+l<=R;j++)B[j-1].x=a[j],B[j-1].y=0;
    	for(int i=mid-l+1;i<=R-l;i++)
    		A[i].x=0,A[i].y=0;
    	for(int i=len;i<limit;i++){
    		A[i].x=0;A[i].y=0;
    		B[i].x=0;B[i].y=0;
    	}
    	FFT(A,1);FFT(B,1);
    	for(int i=0;i<limit;i++)
    		A[i]=A[i]*B[i];
    	FFT(A,-1);
    	for(int i=0;i<limit;i++)
    		A[i].x=A[i].x/limit;
    	for(int i=mid+1;i<=R;i++)
    	{
    		dp[i]+=((ll)(A[i-l-1].x+0.5))%313;
    		dp[i]%=313;
    	}
    	cdq(mid+1,R);
    }
    int main()
    {
    	while(scanf("%d",&n)==1 && n)
    	{
    		for(int i=1;i<=n;i++)a[i]=gi()%Mod;
    		memset(dp,0,sizeof(dp));
    		cdq(1,n);
    		printf("%d
    ",dp[n]);
    	}
    	return 0;
    }
    

    多项式求逆

    挖坑待补

  • 相关阅读:
    线程的五种状态
    ajax回调打开新窗体防止浏览器拦截有效方法
    mysql 如果字段为null自动返回需要的信息sql
    String 与 StringBuffer的区别
    Windows Git中文文件名乱码
    定义函数指针
    hello world
    C++析构函数调用异常问题研究
    企业开发的时候,有可能碰到的问题
    jmap
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10332719.html
Copyright © 2011-2022 走看看