您的位置:首页 > 其它

HDU 5307 He is Flying ——FFT

2017-04-27 21:03 357 查看

卷积的妙用,显然我们可以求出所有符合条件的右端点的和,然后减去左端点的和。

就是最后的答案。然后做一次前缀和,然后就变成了统计差是一个定值的情况。

令$A(s[i])++$ $B(s[i])+=i$

然后卷积一次就可以了,然后用后半部分减去前半部分即可。

并不需要两次FFT

然后发现$0$的情况会导致重叠。所以特判就好了。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define double long double
#define maxn 400005

struct Complex{
double x,y;
Complex () {}
Complex (double _x,double _y) {x=_x;y=_y;}
Complex operator + (Complex a) {return Complex(x+a.x,y+a.y);}
Complex operator - (Complex a) {return Complex(x-a.x,y-a.y);}
Complex operator * (Complex a) {return Complex(x*a.x-y*a.y,x*a.y+y*a.x);}
void init(){x=0;y=0;}
}A[maxn],B[maxn],C[maxn],ans[maxn];

int t,n,a[maxn],sum,rev[maxn],m,len,top;
const double pi=acos(-1.0);

void FFT(Complex * x,int n,int flag)
{
F(i,0,n-1) if (rev[i]>i) swap(x[rev[i]],x[i]);
for (int m=2;m<=n;m<<=1)
{
Complex wn=Complex(cos(2*pi/m),flag*sin(2*pi/m));
for (int i=0;i<n;i+=m)
{
Complex w=Complex(1.0,0);
for (int j=0;j<(m>>1);++j)
{
Complex u=x[i+j],v=x[i+j+(m>>1)]*w;
x[i+j]=u+v;x[i+j+(m>>1)]=u-v;
w=w*wn;
}
}
}
}

int main()
{
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);int flag=1,cnt=0;ll ans0=0;
F(i,1,n){scanf("%d",&a[i]);if(a[i]==0&&flag)cnt++;else{F(i,1,cnt) ans0+=(ll)i*(cnt-i+1);cnt=0;}a[i]+=a[i-1];}
F(i,1,cnt) ans0+=(ll)i*(cnt-i+1);cnt=0;
sum=a
;top=n;a[0]=0;n=2*(sum+1)+3;m=1;len=0;while (m<=n) m<<=1,len++;n=m;
F(i,0,n-1){int ret=0,t=i;F(j,1,len)ret<<=1,ret|=t&1,t>>=1;rev[i]=ret;}
F(i,0,n-1) A[i].init(),B[i].init(),ans[i].init();F(i,0,top) A[sum-a[i]].x+=1.0,B[a[i]].x+=1.0*i;
FFT(A,n,1);FFT(B,n,1);F(i,0,n-1)C[i]=A[i]*B[i];FFT(C,n,-1);F(i,0,n-1)C[i].x=C[i].x/n;
F(i,0,sum) ans[i].x+=C[sum+i].x-C[sum-i].x;
printf("%lld\n",ans0);F(i,1,sum) printf("%lld\n",(ll)(ans[i].x+0.5));
}
}

  

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: