强题!dft!

来源:互联网 发布:管家婆软件多少钱 编辑:程序博客网 时间:2024/05/17 22:58

膜拜!dft!

题目来源

不知道是什么地方的集训题,总之很强就对了.

题目描述

这里写图片描述
这里写图片描述
这里写图片描述

题解

题目描述有点问题,y序列少写了个y0.
题意其实是这样的:
每次把[l,r]的序列取出来,进行dft变换,然后再放回原序列.
取出来进行变换是指,重新编号,并且变换只与[l,r]的序列有关,与原序列无关。

那么怎么做呢?先化简式子?理论上应该要化简式子,但是我的数学水平不足以解决这样的式子,那怎么办?先写个O(n3)的暴力看看.

于是我们可以发现一些规律:
对1,2,3,4进行两次变换之后变成了1,4,3,2;数值没有变,只有位置变化了;
对1,2,3,4,5,6进行两次变换变成了1,6,5,4,3,2.这下发现规律了!L位置的数不变,[L+1,R]的数反序;
那么询问的答案怎么算?根据打表结果,我们发现,这个变换一次之后的模长平方和等于变换之前的模长平方和。
这些结论我真的不会证明,也没有看到什么有用的题解,如果有大佬会证明的,可以在评论区教育我。

于是写个暴力就有50分了,如果用平衡树维护的话可以拿到100分。

Code

贴一份代码:

#include<cstdio>#include<algorithm>using namespace std;#define LL long long#define MAXN 105000int st[MAXN],top;struct node{    int ch[MAXN][2],fa[MAXN],rev[MAXN],tot,root,size[MAXN];    LL val[MAXN],sum[MAXN];    void cal(int p)    {        sum[p]=val[p]+sum[ch[p][0]]+sum[ch[p][1]];        size[p]=size[ch[p][0]]+size[ch[p][1]]+1;        return ;    }    void zg(int x,int d)    {        int y=fa[x],z=fa[y];        if(ch[z][0]==y)        {            ch[z][0]=x;        }        else        {            ch[z][1]=x;        }        fa[x]=z;        ch[y][d]=ch[x][!d];        fa[ch[y][d]]=y;        ch[x][!d]=y;        fa[y]=x;        cal(y);        cal(x);        if(!fa[x])        {            root=x;        }        return ;    }    void Rev(int p)    {        swap(ch[p][0],ch[p][1]);        rev[p]^=1;        return ;    }    void push(int p)    {        if(rev[p])        {            if(ch[p][0])            {                Rev(ch[p][0]);            }            if(ch[p][1])            {                Rev(ch[p][1]);            }            rev[p]^=1;        }        return ;    }    void splay(int x,int to=0)    {        if(x==to)        {            return ;        }        int y,z;        st[++top]=x;        for(int i=x;fa[i]!=to;i=fa[i])        {            st[++top]=fa[i];        }        for(;top;--top)        {            push(st[top]);        }        while(fa[x]!=to)        {            y=fa[x];            z=fa[y];            if(z!=to)            {                if(ch[z][0]==y^ch[y][0]==x)                {                    zg(x,ch[fa[x]][1]==x);                }                else                {                    zg(y,ch[fa[y]][1]==y);                }            }            zg(x,ch[fa[x]][1]==x);        }        return ;    }    void ins(LL v)    {        if(!root)        {            root=1;            ++tot;            sum[tot]=val[tot]=v;            size[tot]=1;            return ;        }        int p=root;        while(ch[p][1])        {            p=ch[p][1];        }        size[++tot]=1;        ch[p][1]=tot;        sum[tot]=val[tot]=v;        fa[tot]=p;        splay(p);        return ;    }    int kth(int k)    {        int p=root;        while(p)        {            push(p);            if(k==size[ch[p][0]]+1)            {                break;            }            else if(k<=size[ch[p][0]])            {                p=ch[p][0];            }            else if(k>size[ch[p][0]]+1)  //因为没写这两个else,我调了3个小时!简直闯了鬼了!             {                k-=size[ch[p][0]]+1;                p=ch[p][1];            }        }        return p;    }    void print()    {        for(int i=2;i<tot;i++)        {            printf("%d ",val[kth(i)]);        }        putchar('\n');        return ;    }}T;int n,q,l,r;void _r(int& x,bool f=0){    char c=getchar();    while(c<'0'||c>'9')    {        f|=(c=='-');        c=getchar();    }    for(x=0;c>='0'&&c<='9';c=getchar())    {        x=(x<<1)+(x<<3)+c-'0';    }    x=f?-x:x;    return ;}int o[30],oo;void _w(LL x){    if(x==0ll)    {        putchar('0');        return ;    }    for(oo=0;x;x/=10ll)    {        o[++oo]=x%10ll;    }    for(;oo;--oo)    {        putchar('0'+o[oo]);    }    return ;}int main(){    //freopen("dft.in","r",stdin);    //freopen("dft.out","w",stdout);    _r(n);    T.ins(0);    for(int i=1,x;i<=n;i++)    {        _r(x);        T.ins(1ll*x*x);    }    T.ins(0);    _r(q);    for(int i=1,a,b,c;i<=q;i++)    {        _r(l);        _r(r);        a=T.kth(l+1);        T.splay(a);        b=T.kth(r+2);        T.splay(b,a);        _w(T.sum[T.ch[b][0]]+T.val[a]);        putchar('\n');        T.Rev(T.ch[b][0]);    }    return 0;}       
原创粉丝点击