HDU5307 He is Flying
2016-06-19 14:41
423 查看
题目链接
1≤n≤105,∑ai≤5×104.
官方题解构造了这样一个多项式:
(∑ixsi)(∑x−si−1)−(∑xsi)(∑(i−1)x−si−1).
其中si=∑ij=1aj(1≤i≤n),s0=0.
然后得到的多项式的xS(1≤S≤∑ai)的系数即为所求的S对应的答案.
一开始看到这个我完全是不知所措的,觉得题解真是用心险恶.
然而这个其实还是好理解的,区间[i,j]的和为S,很容易想到化成sj−si−1=S.而上面的多项式左边两项乘起来是这样:
ixsi⋅x−sj−1=ixsi−sj−1.
右边的两项乘起来是这样:
xsi⋅(j−1)x−sj−1=(j−1)xsi−sj−1.
两个相减就得到了这么个东西:
(i−j+1)xsi−sj−1.
于是十分巧妙地把S体现在了指数上,把要求的区间长度体现在了系数上.
而且这样也避免了遗漏和重复计算,除了S=0的情况,因为S=0可以由si−si得到,也可以由两个相等的前缀和si=sj通过si−sj和sj−si两次计算得到,这样会比较麻烦.而实际上直接在原数组ai上O(n)扫一遍就可以得出S=0的答案了,所以可以另外考虑.
所以接下来只要算那个构造出来的多项式就好.这个可以用FFT,但是由于指数会有负的,我们把指数为负的先加上一个值(比如sn),然后就可以直接用FFT了.
说起来很简单,但是实现还是有点小烦的.
还有这题会卡精度所以要用long double.
总的时间复杂度是O(nlgn).
后来手写了个复数竟然快了近三倍orz…
说写这题涨姿势是因为调试时发现long double要用%Ld输出…
题目大意
给定n个非负整数a1~an,对每个0≤S≤∑ai,输出所有和为S的区间的长度和.1≤n≤105,∑ai≤5×104.
题解
写这题真心涨姿势了…官方题解构造了这样一个多项式:
(∑ixsi)(∑x−si−1)−(∑xsi)(∑(i−1)x−si−1).
其中si=∑ij=1aj(1≤i≤n),s0=0.
然后得到的多项式的xS(1≤S≤∑ai)的系数即为所求的S对应的答案.
一开始看到这个我完全是不知所措的,觉得题解真是用心险恶.
然而这个其实还是好理解的,区间[i,j]的和为S,很容易想到化成sj−si−1=S.而上面的多项式左边两项乘起来是这样:
ixsi⋅x−sj−1=ixsi−sj−1.
右边的两项乘起来是这样:
xsi⋅(j−1)x−sj−1=(j−1)xsi−sj−1.
两个相减就得到了这么个东西:
(i−j+1)xsi−sj−1.
于是十分巧妙地把S体现在了指数上,把要求的区间长度体现在了系数上.
而且这样也避免了遗漏和重复计算,除了S=0的情况,因为S=0可以由si−si得到,也可以由两个相等的前缀和si=sj通过si−sj和sj−si两次计算得到,这样会比较麻烦.而实际上直接在原数组ai上O(n)扫一遍就可以得出S=0的答案了,所以可以另外考虑.
所以接下来只要算那个构造出来的多项式就好.这个可以用FFT,但是由于指数会有负的,我们把指数为负的先加上一个值(比如sn),然后就可以直接用FFT了.
说起来很简单,但是实现还是有点小烦的.
还有这题会卡精度所以要用long double.
总的时间复杂度是O(nlgn).
后来手写了个复数竟然快了近三倍orz…
说写这题涨姿势是因为调试时发现long double要用%Ld输出…
代码
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #define debug(x) cout<<#x<<"="<<x<<endl using namespace std; typedef long long ll; typedef long double ld; const int N=1e5+5,M=(1<<17)+5; const ld pi=acos(-1.0); int sum ,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]; void rd(int &res){ res=0; char c; while(c=getchar(),c<48); do res=(res<<3)+(res<<1)+(c^48); while(c=getchar(),c>47); } 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; } void solve(){ int n; ll ans0=0; rd(n); sum[0]=0; for(int i=1,num,cnt=0;i<=n;++i){ rd(num); sum[i]=sum[i-1]+num; if(!num){ ++cnt; ans0+=1ll*cnt*(cnt+1)/2; } else cnt=0; } printf("%I64d\n",ans0); for(int i=0;i<=sum ;++i){ A[i]=B[i]=0; } for(int i=1;i<=n;++i){ A[sum[i]].real+=i; B[-sum[i-1]+sum ].real+=1; } calc_FFT(sum ,0); for(int i=0;i<=sum ;++i){ A[i]=B[i]=0; } for(int i=1;i<=n;++i){ A[sum[i]].real+=1; B[-sum[i-1]+sum ].real+=i-1; } calc_FFT(sum ,1); for(int i=1;i<=sum ;++i){ printf("%I64d\n",(ll)(ans[0][i+sum ].real-ans[1][i+sum ].real+0.5)); } } int main(){ int cas; rd(cas); while(cas--)solve(); return 0; } /* Jun.19.16 Tags:math,FFT Submissions:5 Exe.Time 1107MS Exe.Memory 18880K Code Len. 2239B */
相关文章推荐
- JavaScript构造函数详解
- jQuery入门 构造函数
- js调用webservice构造SOAP进行身份验证
- 使用Java构造和解析Json数据的两种方法(详解二)
- 使用Java构造和解析Json数据的两种方法(详解一)
- java中的静态代码块、构造代码块、构造方法详解
- Python类方法__init__和__del__构造、析构过程分析
- 网络资料备忘录
- 谱相关的资料备忘
- 关于获得ArrayAdapter对象的细节
- 类的继承与派生
- 探讨“临时对象”(temporary object)
- C语言版 256点FFT算法
- 【HDU 5366】The mook jong 详解
- 【HDU 2136】Largest prime factor 详细图解
- 【HDU 1568】Fibonacci 数学公式 详解
- 一幅图弄清DFT与DTFT,DFS的关系
- HDU 1568
- HDU1290
- DSP Builder