zoukankan      html  css  js  c++  java
  • hdu5730 Shell Necklace 【分治fft】

    题目

    简述:

    有一段长度为n的贝壳,将其划分为若干段,给出划分为每种长度的方案数,问有多少种划分方案

    题解

    (f[i])表示长度为(i)时的方案数
    不难得dp方程:

    [f[i] = sumlimits_{j=0}^{i} a[j] * f[i - j] ]

    考虑转移
    直接转移是(O(n^2))
    如何优化?
    容易发现这个转移方程非常特别,是一个卷积的形式
    考虑fft

    分治fft##

    分治fft解决的就是这样一个转移方程的快速计算的问题

    [f[i] = sumlimits_{j=0}^{i} a[j] * f[i - j] ]

    考虑cdq分治的模式:
    我们先处理左半区间,然后用左半区间的(f[i])来更新右半区间的答案
    具体地,左半区间对右边一个位置(r)的贡献是:

    [sumlimits_{i=l}^{mid} f[i] * a[r - i] ]

    也是一个卷积的形式,为多项式乘积的第(r)
    如此我们便可以用(f[i])(a[i])构造两个多项式,作fft,然后直接将相应位置的值累加到右半边相应位置的(f[i])中去

    我们便解决了这道题

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 400005,maxm = 100005,INF = 1000000000,P = 313;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    const double pi = acos(-1);
    struct E{
    	double r,i;
    	E(){}
    	E(double a,double b):r(a),i(b){}
    	E operator =(const int& b){
    		r = b; i = 0;
    		return *this;
    	}
    };
    inline E operator +(const E& a,const E& b){
    	return E(a.r + b.r,a.i + b.i);
    }
    inline E operator -(const E& a,const E& b){
    	return E(a.r - b.r,a.i - b.i);
    }
    inline E operator *(const E& a,const E& b){
    	return E(a.r * b.r - a.i * b.i,a.r * b.i + b.r * a.i);
    }
    inline E operator *=(E& a,const E& b){
    	return (a = a * b);
    }
    inline E operator /(E& a,const double& b){
    	return E(a.r / b,a.i / b);
    }
    inline E operator /=(E& a,const double& b){
    	return (a = a / b);
    }
    int n,m,L,R[maxn];
    void fft(E* a,int f){
    	for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
    	for (int i = 1; i < n; i <<= 1){
    		E wn(cos(pi / i),f * sin(pi / i));
    		for (int j = 0; j < n; j += (i << 1)){
    			E w(1,0);
    			for (int k = 0; k < i; k++,w *= wn){
    				E x = a[j + k],y = w * a[j + k + i];
    				a[j + k] = x + y; a[j + k + i] = x - y;
    			}
    		}
    	}
    	if (f == -1) for (int i = 0; i < n; i++) a[i] /= n;
    }
    E A[maxn],B[maxn];
    int N,a[maxn],f[maxn];
    void solve(int l,int r){
    	if (l == r){
    		f[l] = (f[l] + a[l]) % P;
    		return;
    	}
    	int mid = l + r >> 1;
    	solve(l,mid);
    	n = mid - l + 1;
    	for (int i = 0; i < n; i++) A[i] = f[l + i];
    	m = r - l + 1;
    	for (int i = 0; i < m; i++) B[i] = a[i + 1];
    	m = n + m; L = 0;
    	for (n = 1; n <= m; n <<= 1) L++;
    	for (int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	fft(A,1); fft(B,1);
    	for (int i = 0; i < n; i++) A[i] *= B[i];
    	fft(A,-1);
    	for (int i = mid + 1; i <= r; i++){
    		f[i] = (f[i] + (int)floor(A[i - l - 1].r + 0.5) % P) % P;
    	}
    	for (int i = 0; i < n; i++) A[i] = B[i] = 0;
    	solve(mid + 1,r);
    }
    int main(){
    	while ((~scanf("%d",&N)) && N){
    		for (int i = 1; i <= N; i++){
    			a[i] = read() % P;
    			f[i] = 0;
    		}
    		solve(1,N);
    		printf("%d
    ",f[N]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    python 的基础 学习 第六天 基础数据类型的操作方法 字典
    python 的基础 学习 第五天 基础数据类型的操作方法
    python 的基础 学习 第四天 基础数据类型
    ASP.NET MVC 入门8、ModelState与数据验证
    ASP.NET MVC 入门7、Hellper与数据的提交与绑定
    ASP.NET MVC 入门6、TempData
    ASP.NET MVC 入门5、View与ViewData
    ASP.NET MVC 入门4、Controller与Action
    ASP.NET MVC 入门3、Routing
    ASP.NET MVC 入门2、项目的目录结构与核心的DLL
  • 原文地址:https://www.cnblogs.com/Mychael/p/8761814.html
Copyright © 2011-2022 走看看