hdu5307 He is Flying

题目描述

题解:

首先一看区间和就知道是预处理前缀和。

区间$[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\n",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\n",ans[i]-(ll)(C[i+s[n]].x+0.1));
    }
    return 0;
}

 

posted @ 2019-01-17 19:23  LiGuanlin  阅读(142)  评论(0编辑  收藏  举报