题解:
首先一看区间和就知道是预处理前缀和。
区间$[l,r]$求和是$s[r]-s[l-1]$。(废话)
然后感觉这道题好毒瘤啊。。。
好像是构造。
后来才知道官方题解真的给了个多项式。
具体实现就是,有两个多项式$A,B$,
第一次,对于这个前缀和$s$,我们让$A[s]+=s_{len},B[S-s]++$,
其中$S$指总和。
然后求$A*B$,得到的多项式第$i+S$项系数就是所有区间和为$i$的区间的$r$之和。
第二次,我们让$A[s]++,B[S-s]+=s_{len}$,
$A*B$的第$i+S$系数就是$l-1$之和。
最后减一下就好了。
但是算$0$时会有麻烦。比如区间我减我自己得到个$0$,
读进来的时候维护一下连续的$0$对答案的影响即可。
$FFT$精度不够要开$long double$。
出题人真$nb$。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const long double Pi = acos(-1.0); const int N = 400050; template<typename T> inline void read(T&x) { T f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} x = f*c; } struct cp { long double x,y; cp(){} cp(long double x,long double y):x(x),y(y){} cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);} cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);} cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }; int to[N]; void fft(cp *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int o=0;o<i;o++,w=w*w0) { cp w1 = a[j+o],w2 = a[j+o+i]*w; a[j+o] = w1+w2; a[j+o+i] = w1-w2; } } } if(k==-1) for(int i=0;i<len;i++) a[i].x/=len; } int T,n,a[N],s[N],lim=1,l; ll ans[N]; cp A[N],B[N],C[N]; int main() { read(T); while(T--) { read(n); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(ans,0,sizeof(ans)); ll ans0 = 0,cnt = 0; for(int i=1;i<=n;i++) { read(a[i]); s[i] = s[i-1]+a[i]; if(!a[i]) { cnt++; ans0+=cnt*(cnt+1)/2; }else cnt=0; } printf("%I64d ",ans0); lim = 1,l = 0; while(lim<=2*s[n])lim<<=1,l++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1))); for(int i=1;i<=n;i++) { A[s[i]].x+=i; B[s[n]-s[i-1]].x++; } fft(A,lim,1),fft(B,lim,1); for(int i=0;i<lim;i++)C[i]=A[i]*B[i]; fft(C,lim,-1); for(int i=1;i<=s[n];i++) ans[i]+=(ll)(C[i+s[n]].x+0.1); for(int i=0;i<lim;i++)A[i]=B[i]=cp(0,0); for(int i=1;i<=n;i++) { A[s[i]].x++; B[s[n]-s[i-1]].x+=i-1; } fft(A,lim,1),fft(B,lim,1); for(int i=0;i<lim;i++)C[i]=A[i]*B[i]; fft(C,lim,-1); for(int i=1;i<=s[n];i++) printf("%I64d ",ans[i]-(ll)(C[i+s[n]].x+0.1)); } return 0; }