Hdu5307 He is Flying

题意:给定n个非负整数a1~an,对每个0≤S≤∑ai,输出所有和为S的区间的长度和。

思路:推荐且来自https://blog.csdn.net/kyleyoung_ymj/article/details/51712329

       这个题的构造公式真的是神奇,我主要也通过这道题学习了FFT算法,关于这题的构造公式的思路我还是得再想想,线面主要整理一些关于快速傅里叶变换

在acm中的FFT主要就做了一件事,两个母函数相乘,如果两母函数都是n,那么相乘运算复杂度是O(n^2),用FFT的方法可以变成O(n log n),相应的也可以做大数乘法变成(n log n)。主要利用了傅里叶变换的一些性质,具体推荐知识点下面的博客。

具体知识点强力推荐:https://blog.csdn.net/herano/article/details/71213373

另外:(关键的一点)

代码参考:https://blog.csdn.net/kyleyoung_ymj/article/details/51712329

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<vector>
#include<cstdio>
#include<time.h>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ld;
const ld pi=acos(-1.0);

const int N=1e5+5,M=(1<<17)+5;//都100000多
int sum[N],rev[M];

struct C{//复数
    ld real,imag;
    C(ld real=0,ld imag=0):real(real),imag(imag){}
    friend C operator +(C A,C B){
        return C(A.real+B.real,A.imag+B.imag);
    }
    friend C operator -(C A,C B){
        return C(A.real-B.real,A.imag-B.imag);
    }
    friend C operator *(C A,C B){
        return C(A.real*B.real-A.imag*B.imag,A.imag*B.real+A.real*B.imag);
    }
}A[M],B[M],ans[2][M];//A*B两多项式
void FFT(C *arr,int n,int flag)
{
    for(int i=0;i<n;++i)
        if(i<rev[i])
            swap(arr[i],arr[rev[i]]);
    for(int m=2;m<=n;m<<=1){
        C wm(cos(2*pi/m),flag*sin(2*pi/m));
        for(int i=0;i<n;i+=m){
            C w(1,0);
            for(int j=0;j<m>>1;++j,w=w*wm){
                C x=arr[i+j],y=w*arr[i+j+(m>>1)];
                arr[i+j]=x+y;
                arr[i+j+(m>>1)]=x-y;
            }
        }
    }
}
void calc_FFT(int n,bool id){
    int _n=n,m=n<<1,S=0;
    for(n=1;n<=m;n<<=1,++S);
    rev[0]=0;
    for(int i=1;i<n;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(S-1));
    for(int i=_n+1;i<n;++i)
        A[i]=B[i]=0;
    FFT(A,n,1);
    FFT(B,n,1);
    for(int i=0;i<n;++i)
        ans[id][i]=A[i]*B[i];
    FFT(ans[id],n,-1);
    for(int i=0;i<=m;++i)
        ans[id][i].real/=n;
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        int n,num;
        ll ans0=0;
        int p=0;
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            sum[i]=sum[i-1]+num;
            if(!num)
            {
                ++p;
                ans0=ans0+1ll*p*(p+1)/2;
            }
            else p=0;
        }
        cout<<ans0<<endl;
        for(int i=0;i<=sum[n];i++)
        {
            A[i]=B[i]=0;
        }
        for(int i=1;i<=n;i++)//构造多项式
        {
            A[sum[i]].real+=i;
            B[sum[n]-sum[i-1]].real+=1;
        }
        calc_FFT(sum[n],0);
        for(int i=0;i<=sum[n];i++)
        {
            A[i]=B[i]=0;
        }
        for(int i=1;i<=n;i++)//构造多项式
        {
            A[sum[i]].real+=1;
            B[sum[n]-sum[i-1]].real+=(i-1);
        }
        calc_FFT(sum[n],1);
        for(int i=1;i<=sum[n];i++)
        {
            cout<<(ll)(ans[0][i+sum[n]].real-ans[1][i+sum[n]].real+0.5)<<endl;//注意控制精度
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81106043
he