HDU5307 He is Flying 【FFT】
阿新 • • 發佈:2018-12-26
題目描述:
n段連續編號為1~n的道路,每段長度為一個非負整數,道路總長<=50000,n<=100000
從編號為
的路走到編號為
的路所得到的快樂值為
對於每個
,(
),求出走所有長度為S的路(可以是幾段接起來的)得到的快樂值
簡述:數列
,總和為
,求
,所有區間和為k的區間長度和
題目分析:
把加法運算轉化為冪的次數,再利用係數得到答案
那麼所有的區間就可以表示成多項式相乘的形式:
乘出來的
項的係數就是長度為k的區間的個數,當i<=j時次數為非正數,對答案無影響
(所以要特殊處理長度為0的情況,預處理,O(n)掃一遍即可)
那麼再考慮把區間長度加進去,就是:
做兩次FFT即可,第二個多項式由於次數為負,所以右移sum次
- double最多有15位有效數字,而此題答案可能大於1015,所以要用 long double,或者寫NTT,不過模數要很大,還要寫大數模乘法。。。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 400005
using namespace std;
const long double Pi = acos(-1);
struct complex
{
long double r,i;
complex(long double _r=0,long double _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,r*t.i+i*t.r);}
}x1[maxn],x2[maxn],w,wn;
void change(complex *x,int len)
{
for(int i=1,j=len/2,k;i<len-1;i++)
{
if(i<j) swap(x[i],x[j]);
for(k=len/2;j>=k;j-=k,k>>=1);
j+=k;
}
}
void fft(complex *x,int len,int flg)
{
change(x,len);
for(int i=2;i<=len;i<<=1)
{
wn=complex(cos(2*Pi*flg/i),sin(2*Pi*flg/i));
for(int j=0;j<len;j+=i)
{
w=complex(1,0);
for(int k=j;k<j+i/2;k++)
{
complex u=x[k],v=w*x[k+i/2];
x[k]=u+v,x[k+i/2]=u-v;
w=w*wn;
}
}
}
if(flg==-1) for(int i=0;i<len;i++) x[i].r/=len;
}
int T,n,s[maxn];
long long ans[maxn],sum[maxn];
int main()
{
for(int i=1;i<=100000;i++) sum[i]=sum[i-1]+i*(i+1)/2;//0的預處理
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&s[i]),s[i]+=s[i-1];
int len=1;while(len<=2*s[n]) len<<=1;
for(int i=0;i<len;i++) x1[i]=x2[i]=complex();
for(int i=1;i<=n;i++) x1[s[i]].r+=i;
for(int i=0;i<n;i++) x2[s[n]-s[i]].r++;
fft(x1,len,1),fft(x2,len,1);
for(int i=0;i<len;i++) x2[i]=x1[i]*x2[i];
fft(x2,len,-1);
for(int i=0;i<len;i++) ans[i]=(long long)(x2[i].r+0.5);
for(int i=0;i<len;i++) x1[i]=x2[i]=complex();
for(int i=1;i<=n;i++) x1[s[i]].r++;
for(int i=0;i<n;i++) x2[s[n]-s[i]].r+=i;
fft(x1,len,1),fft(x2,len,1);
for(int i=0;i<len;i++) x2[i]=x1[i]*x2[i];
fft(x2,len,-1);
for(int i=0;i<len;i++) ans[i]-=(long long)(x2[i].r+0.5);
ans[s[n]]=0,s[n+1]=-1;
for(int i=1,tmp=0;i<=n+1;i++)
if(s[i]==s[i-1]) tmp++;
else ans[s[n]]+=sum[tmp],tmp=0;
for(int i=0;i<=s[n];i++) printf("%lld\n",ans[i+s[n]]);
}
}