zoukankan      html  css  js  c++  java
  • [hdu 5307] He is Flying (FFT)

    题意

    给出长度为nn的数列aa,记i=1nai=s(s<=50000)sum_{i=1}^na_i=s(s<=50000)
    对于任意k[0,s]kin[0,s],求出区间和为kk的区间的长度之和

    题目分析

    有了几道fft题的经验,套路就是把可加性的计算化为幂的次数做多项式卷积

    Ans(k)=i=1nj=0i1[sum(i)sum(j)==k](ij)=i=1nj=0i1[sum(i)sum(j)==k]i............(1)i=1nj=0i1[sum(i)sum(j)==k]j............(2)large egin{aligned} Ans(k)=&sum_{i=1}^nsum_{j=0}^{i-1}[sum(i)-sum(j)==k](i-j)\ =&sum_{i=1}^nsum_{j=0}^{i-1}[sum(i)-sum(j)==k]i............(1)\ &-sum_{i=1}^nsum_{j=0}^{i-1}[sum(i)-sum(j)==k]j............(2)\ end{aligned}
    分别把(1),(2)(1),(2)看成两个多项式,做FFT即可

    • (1)(1)举例

    第一个多项式:
    sum(i)的次数对应的系数加上i(1<=i<=n)
    第二个多项式:
    -sum(i)的次数对应的系数加上1(0<=i<=n-1)

    由于负数次幂FFT无法处理,于是加上一个ss,即

    第一个多项式:
    sum(i)的次数对应的系数加上i(1<=i<=n)
    第二个多项式:
    s-sum(i)的次数对应的系数加上1(0<=i<=n-1)

    kk所对应的答案存在k+sk+s的次数的系数上

    • (2)(2)可以类比

    • 注意特判一下k=0k=0的情况

    • 还有这道题卡精度,必须用Long Double,否则会WA(也可以写NTT)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    typedef long double LD; //卡精度,不然会WA
    const int MAXN = 1<<17;
    const LD Pi = acos(-1.0);
    struct complex
    {
    	LD r, i;
    	complex(LD _r = 0, LD _i = 0):r(_r), i(_i){}
    
    	complex operator +(const complex &t)const
    	{ return complex(r + t.r, i + t.i); }
    
    	complex operator -(const complex &t)const
    	{ return complex(r - t.r, i - t.i); }
    	
    	complex operator *(const complex &t)const
    	{ return complex(r*t.r - i*t.i, i*t.r + t.i*r); }
    	
    	
    }a1[MAXN], a2[MAXN];
    
    inline void change(complex arr[], const int& len)
    {
    	for(register int i = 1, j = len/2; i < len-1; ++i)
    	{
    		if(i < j) swap(arr[i], arr[j]);
    		int k = len/2;
    		while(j >= k) j -= k, k>>=1;
    		j += k;
    	}
    }
    
    inline void fft(complex arr[], const int& len, const int& flg)
    {
    	change(arr, len);
    	for(register int i = 2; i <= len; i<<=1)
    	{
    		complex wn = complex(cos(2*Pi*flg/i), sin(2*Pi*flg/i));
    		for(register int j = 0; j < len; j += i)
    		{
    			complex w = complex(1, 0);
    			for(register int k = j; k < j + i/2; ++k)
    			{
    				complex A0 = arr[k];
    				complex wA1 = w * arr[k + i/2];
    				arr[k] = A0 + wA1;
    				arr[k + i/2] = A0 - wA1;
    				w = w * wn;
    			}
    		}
    	}
    	if(flg == -1)
    		for(register int i = 0; i < len; ++i)
    			arr[i].r /= len;
    }
    
    int sum[MAXN], S;
    
    LL ans[MAXN], pres[MAXN];
    
    int main ()
    {
    	for(LL i = 1; i <= 100000; ++i) //预处理
    		pres[i] = pres[i-1] + i*(i+1)/2;
    	int T, n;
    	scanf("%d", &T);
    	while(T--)
    	{
    		scanf("%d", &n);
    		int last = 0; LL ans0 = 0;
    		for(int i = 1, x; i <= n; ++i)
    		{
    			scanf("%d", &x), sum[i] = sum[i-1] + x;
    			if(!x) ++last;
    			else ans0 += pres[last], last = 0;
    		}
    		printf("%lld
    ", ans0 += pres[last]); //0特判
    	
    		S = sum[n];
    	
    		int len = 1;
    		while(len < (S<<1)) len<<=1;
    		
    		for(int i = 0; i < len; ++i) a1[i] = a2[i] = complex(); //Part 1
    		for(int i = 1; i <= n; ++i)
    		{
    			a1[sum[i]].r += i;
    			if(i<n) a2[S-sum[i]].r += 1;
    		}
    		a2[S-0].r += 1; //i = sum[i] = 0
    		fft(a1, len, 1); fft(a2, len, 1);
    		for(int i = 0; i < len; ++i) a2[i] = a1[i] * a2[i];
    		fft(a2, len, -1);
    		for(int i = S+1; i <= (S<<1); ++i) ans[i-S] = LL(a2[i].r + 0.5);
    		
    		
    		for(int i = 0; i < len; ++i) a1[i] = a2[i] = complex(); //Part 2
    		for(int i = 1; i <= n; ++i)
    		{
    			a1[sum[i]].r += 1;
    			if(i < n) a2[S-sum[i]].r += i;
    		}
    		fft(a1, len, 1); fft(a2, len, 1);
    		for(int i = 0; i < len; ++i) a2[i] = a1[i] * a2[i];
    		fft(a2, len, -1);
    	
    		for(int i = S+1; i <= (S<<1); ++i)
    			printf("%lld
    ", ans[i-S] - LL(a2[i].r + 0.5));
    	}
    }
    
  • 相关阅读:
    python入门之json与pickle数据序列化
    python入门之迭代器
    python入门之生成器
    阿里云-域名免费申请ssl证书过程
    mongodb的基本命令操作
    kibana通过nginx配置访问用户验证
    Java中常用的加密算法MD5,SHA,RSA
    Weka关联规则分析
    Swing实现系统托盘
    Swing实现右下角消息框
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039448.html
Copyright © 2011-2022 走看看