HDU5307 He is Flying
原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5307
题意:
给定n个非负整数
a1...an
a
1
.
.
.
a
n
,对所有
0≤S≤∑ai
0
≤
S
≤
∑
a
i
,输出所有
ai
a
i
和为S的区间的长度和.
数据范围
1≤n≤105
1
≤
n
≤
10
5
,
∑ai≤5×104.
∑
a
i
≤
5
×
10
4
.
题解:
令
si
s
i
为
ai
a
i
的前缀和,那么对于区间[i,j],对
si−sj−1
s
i
−
s
j
−
1
有着
j−i+1
j
−
i
+
1
的贡献。
易于想到的是
xsi∗x−sj−1=xsi−sj−1
x
s
i
∗
x
−
s
j
−
1
=
x
s
i
−
s
j
−
1
,
由于每个区间的贡献是长度
i−j+1
i
−
j
+
1
,
可以构造出多项式
∑xsii ×xsi−1−∑xsi ×xsi−1(i−1)
∑
x
s
i
i
×
x
s
i
−
1
−
∑
x
s
i
×
x
s
i
−
1
(
i
−
1
)
xs
x
s
的系数就是s的答案。
用FFT计算即可。
1A开心。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
#define LD long double
const long double Pi=acos(-1);
using namespace std;
const int N=200005;
inline int read()
{
int ret=0,w=1; char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret*w;
}
int T,n,s[N],R[N],p,len;
LL ans[N];
struct Virt
{
LD r,i;
Virt(){}
Virt(LD r,LD i):r(r),i(i){}
Virt operator+(const Virt &A){return Virt(r+A.r,i+A.i);}
Virt operator-(const Virt &A){return Virt(r-A.r,i-A.i);}
Virt operator*(const Virt &A){return Virt(r*A.r-i*A.i,r*A.i+i*A.r);}
}a[N],b[N],omg[N],_omg[N];
void FFT(Virt *x,int opt)
{
for(int i=0;i<len;i++) if(i<R[i]) swap(x[i],x[R[i]]);
Virt *w; if(opt==1) w=omg; else w=_omg;
for(int m=2;m<=len;m<<=1)
{
int l=m>>1;
for(int j=0;j<len;j+=m)
for(int i=0;i<l;i++)
{
Virt y=w[len/m*i]*x[j+i+l];
x[j+i+l]=x[j+i]-y;
x[j+i]=x[j+i]+y;
}
}
if(opt==-1) for(int i=0;i<len;i++) x[i].r/=len;
}
int main()
{
T=read();
while(T--)
{
n=read(); LL ret=0; LL cnt=0; s[0]=0;
for(int i=1;i<=n;i++)
{
s[i]=read();
if(s[i]==0) {cnt++,ret+=1LL*(1LL+cnt)*cnt/2LL;}
else cnt=0;
s[i]+=s[i-1];
}
printf("%lld\n",ret);
for(p=0,len=1;len<=2*s[n];len<<=1,p++);
for(int i=0;i<len;i++){omg[i]=Virt(cos(2.0*Pi/(LD)len*i),sin(2.0*Pi/(LD)len*i)); _omg[i]=Virt(omg[i].r,-omg[i].i);}
R[0]=0; for(int i=1;i<len;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(p-1));
for(int i=0;i<=len;i++) a[i]=b[i]=Virt(0,0);
for(int i=1;i<=n;i++) {a[s[i]].r+=(LD)i; b[-s[i-1]+s[n]].r+=(LD)1.0;}
FFT(a,1); FFT(b,1);
for(int i=0;i<len;i++) a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=1;i<=s[n];i++) ans[i]=(LL)(a[i+s[n]].r+0.5);
for(int i=0;i<=len;i++) a[i]=b[i]=Virt(0,0);
for(int i=1;i<=n;i++) {a[s[i]].r+=1.0; b[-s[i-1]+s[n]].r+=(LD)(i-1);}
FFT(a,1); FFT(b,1);
for(int i=0;i<len;i++) a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=1;i<=s[n];i++) ans[i]-=(LL)(a[i+s[n]].r+0.5);
for(int i=1;i<=s[n];i++) printf("%lld\n",ans[i]);
}
return 0;
}