HDU5751Eades

先处理连续一段中最大值出现位置然后用FFT计算出各个最大值出现次数时的线段树 累加答案

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<complex>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>

using namespace std;
#define ll long long
char c;
inline void read(int&a)
{a=0;do c=getchar();while(c<'0'||c>'9');while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();}
int n,m;
int Rev[600000];
inline void Bg(int n)
{
    int L=0;
    while((1<<L)^n)L++;
    for(int i=0;i<n;i++)Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(L-1));
}
#define com complex<double>
const   
    double pi=acos(-1);
com A[600000],B[600000];
int S[600000];
com C[600000];
inline void Rader(com* a,int n)
{
    for(int i=0;i<n;i++)if(Rev[i]>i)swap(a[Rev[i]],a[i]);

}
/*
inline void FFT(com *a,int n,int f)
{
    Rader(a,n);
    for(int i=1;i<n;i<<=1)
        {
            com w0(cos(pi/i),f*sin(pi/i));
            for(int j=0;j<n;j+=i<<1)
                {
                    com w(1,0);
                    for(int k=0;k<i;k++)
                    {
                        com L=a[j+k],R=w*a[j+k+i];
                        a[j+k]=L+R;
                        a[j+k+i]=L-R;
                        w=w*w0;
                    }   
                }
        }
    if(f==-1)
        for(int i=0;i<n;i++)
            a[i]/=n;
}
*/
void FFT(com* a,int len,int flag)
{

    Rader(a,len);
    for(int i=1;i<len;i<<=1)
    {
        com W(cos(pi/i),flag*sin(pi/i));
        for(int j=0;j<len;j+=i<<1)
        {
            com W0(1,0);
            for(int k=0;k<i;k++)
            {
                com x=a[j+k],y=W0*a[j+k+i];
                a[j+k]=x+y;
                a[j+k+i]=x-y;
                W0*=W;
            }
        }
    }
    if(flag==-1)
    for(int i=0;i<len;i++)a[i]/=len;

}


int Val[60001];
int     L[60001],R[60001];

vector<int> Q[60001];

inline bool cmp(int a,int b){return abs(a)<abs(b);}

int main()
{
    int T;
    read(T);
    while(T--)
    {
        int n;
        read(n);

        for(int i=1;i<=n;i++)
            Q[i].clear();
        for(int i=1;i<=n;i++)
        read(Val[i]),Q[Val[i]].push_back(i);
        for(int i=1;i<=n;i++)
        {
            L[i]=i;
            while(L[i]>1&&Val[i]>=Val[L[i]-1])L[i]=L[L[i]-1];
            Q[Val[i]].push_back(-L[i]+1);
        }
        for(int i=n;i;i--)
        {
            R[i]=i;
            while(R[i]<n&&Val[i]>=Val[R[i]+1])R[i]=R[R[i]+1];
            Q[Val[i]].push_back(-R[i]-1);
        }
        for(int i=1;i<=n;i++)sort(Q[i].begin(),Q[i].end(),cmp);
        for(int i=1;i<=n;i++)
        if(!Q[i].empty())
        {
            int l=0,r=l+1;
            while(l<Q[i].size())
                {
                    while(l+1<Q[i].size()&&Q[i][l+1]<=0)
                    l++;
                    if(l+1==Q[i].size())break;
                    r=l+1;          
                    while(Q[i][r]>0)
                        r++;
                    int tl=r-l,len=1;
                    while(tl>len)len*=2;
                    len*=2;
                    //if(len<=4)len*=2;
                    //len*=2;
                    for(int j=0;j<len;j++)C[j]=A[j]=0;
                    Bg(len);
                    A[0]=Q[i][l+1]-abs(Q[i][l]-1)+1;
                    for(int j=1;j<tl-1;j++)
                    A[j]=Q[i][l+j+1]-Q[i][l+j]; 
                    A[tl-1]=abs(Q[i][r]+1)-Q[i][r-1]+1;                 
                    for(int j=0;j<tl-1;j++)C[j]=A[tl-1-j-1];
                    FFT(A,len,1);
                    FFT(C,len,1);
                    for(int j=0;j<len;j++)B[j]=A[j]*C[j];
                    FFT(B,len,-1);

                    for(int j=0;j<tl-1;j++)
                    {
                        int T=int(B[j+tl-1].real()+0.5);
                        S[j+1]+=T;
                    }
                    l=r+1;
                }
        }
        ll Ans=0;
        for(int i=1;i<=n;i++)
            Ans+=i^S[i],S[i]=0;
        cout<<Ans<<endl;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值