zoukankan      html  css  js  c++  java
  • bzoj 3527: [Zjoi2014]力 FFT

    首先我们知道(displaystyle E_j=sum_{i<j}frac{q_i}{(i-j)^2}-sum_{i>j}frac{q_i}{(i-j)^2}),

    (displaystyle g[i]=frac{1}{i^2}),因为(g)是偶函数,所以(displaystyle E_j=sum_{i=0}^{j-1} q_i g[j-i]-sum_{i=j+1}^n q_ig[j-i])

    前面这东西很明显就是卷积,处理后面就要发挥人类智慧了,将(q_i) 翻转成新数组(q_i'),原来的式子就成了

    (displaystyle E_j=sum_{i=0}^{j-1} q_i g[j-i]-sum_{i=0}^{j-1} q_i'g[j-i]),

    后面这东西也变成卷积啦,用FFT处理一下就ok啦。

    时间复杂度O(n log n).

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define DB double
    using namespace std;
    int n, lim = 1, tmp;
    const DB PI = acos(-1);
    const int N = 400010;
    struct lmaginary 
    {
    	DB x, y;
    	lmaginary(double X = 0, double Y = 0) {x = X, y = Y;}
    	friend lmaginary operator +(const lmaginary &a, const lmaginary &b)
    	{return (lmaginary) {a.x + b.x, a.y + b.y};}
    	friend lmaginary operator -(const lmaginary &a, const lmaginary &b)
    	{return (lmaginary) {a.x - b.x, a.y - b.y};}
    	friend lmaginary operator *(const lmaginary &a, const lmaginary &b)
    	{return (lmaginary) {a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x};}
    } f1[N], f2[N], g[N];
    DB q[N];
    int r[N];
    void FFT(lmaginary *A, int lim, int opt) 
    {
    	for (int i = 0; i < lim; ++i)
    		if (i < r[i])swap(A[i], A[r[i]]);
    	for (int mid = 1; mid < lim; mid <<= 1) 
    	{ //长度的一半
    		lmaginary wn(cos(PI / mid), opt * sin(PI / mid));
    		for (int len = mid << 1, j = 0; j < lim; j += len) 
    		{
    			lmaginary w((DB)1, (DB)0);
    			for (int k = j; k < mid + j; ++k, w = w * wn) 
    			{
    				lmaginary a = A[k], b = w * A[k + mid];
    				A[k] = a + b;
    				A[k + mid] = a - b;
    			}
    		}
    	}
    }
    void YYCH() 
    {
    	for (int i = 1; i <= n; ++i) 
    	{
    		g[i].x = (1.0 / i / i);
    		f1[i].x = f2[n - i + 1].x = q[i];
    	}
    	while (lim < 2 * n)lim <<= 1, ++tmp;
    	for (int i = 0; i < lim; ++i)
    		r[i] = (r[i >> 1] >> 1) | ((i & 1) << (tmp - 1));
    }
    int main() 
    {
    	cin >> n;
    	for (int i = 1; i <= n; ++i)scanf("%lf", &q[i]);
    	YYCH();
    	FFT(f1, lim, 1); FFT(f2, lim, 1); FFT(g, lim, 1);
    	for (int i = 0; i < lim; ++i)
    		f1[i] = f1[i] * g[i], f2[i] = f2[i] * g[i];
    	FFT(f1, lim, -1); FFT(f2, lim, -1);
    	for (int i = 1; i <= n; ++i)
    		printf("%f
    ", (f1[i].x - f2[n - i + 1].x) / lim);
    	return 0;
    }
    
  • 相关阅读:
    LeetCode 40. 组合总和 II(Combination Sum II)
    LeetCode 129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers)
    LeetCode 60. 第k个排列(Permutation Sequence)
    LeetCode 47. 全排列 II(Permutations II)
    LeetCode 46. 全排列(Permutations)
    LeetCode 93. 复原IP地址(Restore IP Addresses)
    LeetCode 98. 验证二叉搜索树(Validate Binary Search Tree)
    LeetCode 59. 螺旋矩阵 II(Spiral Matrix II)
    一重指针和二重指针
    指针的意义
  • 原文地址:https://www.cnblogs.com/wljss/p/12006629.html
Copyright © 2011-2022 走看看