hdu 5751 Eades FFT(BC Round 84 E)

我们可以用优先队列什么的随便搞搞,但是由于连续的需要枚举个数,所以复杂度是n^2的,但是呢我们发现用twopoint时移动相当于一个卷积,一直一个从前往后,一个从后往前,然后这个问题就解决了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std ;
typedef long long LL ;
const int maxn=120005;
#define clr( a , x ) memset ( a , x , sizeof a )

const int N = 524300 ;
int n , pos[N] ;

namespace FFT {
    struct comp {
        double r , i ;
        comp ( double _r = 0 , double _i = 0 ) : r ( _r ) , i ( _i ) {}
        comp operator + ( const comp& x ) {
            return comp ( r + x.r , i + x.i ) ;
        }
        comp operator - ( const comp& x ) {
            return comp ( r - x.r , i - x.i ) ;
        }
        comp operator * ( const comp& x ) {
            return comp ( r * x.r - i * x.i , i * x.r + r * x.i ) ;
        }
        comp conj () {
            return comp ( r , -i ) ;
        }
    } A[N] , B[N] ;
    
    const double pi = acos ( -1.0 ) ;
    void FFT ( comp a[] , int n , int t ) {
        for ( int i = 1 ; i < n ; ++ i ) if ( pos[i] > i ) swap ( a[i] , a[pos[i]] ) ;
        for ( int d = 0 ; ( 1 << d ) < n ; ++ d ) {
            int m = 1 << d , m2 = m << 1 ;
            double o = pi * 2 / m2 * t ;
            comp _w ( cos ( o ) , sin ( o ) ) ;
            for ( int i = 0 ; i < n ; i += m2 ) {
                comp w ( 1 , 0 ) ;
                for ( int j = 0 ; j < m ; ++ j ) {
                    comp& A = a[i + j + m] , &B = a[i + j] , t = w * A ;
                    A = B - t ;
                    B = B + t ;
                    w = w * _w ;
                }
            }
        }
        if ( t == -1 ) for ( int i = 0 ; i < n ; ++ i ) a[i].r /= n ;
    }
    void mul ( int *a , int *b , LL *c ,int k) {
        int i , j ;
        for ( i = 0 ; i < k ; ++ i ) A[i] = comp ( a[i] , b[i] ) ;
        j = __builtin_ctz ( k ) - 1 ;
        for ( int i = 0 ; i < k ; ++ i ) {
            pos[i] = pos[i >> 1] >> 1 | ( ( i & 1 ) << j ) ;
        }
        FFT ( A , k , 1 ) ;
        for ( int i = 0 ; i < k ; ++ i ) {
            j = ( k - i ) & ( k - 1 ) ;
            B[i] = ( A[i] * A[i] - ( A[j] * A[j] ).conj () ) * comp ( 0 , -0.25 ) ;
        }
        FFT ( B , k , -1 ) ;
        for ( int i = 0 ; i < k ; ++ i ) {
            c[i] = ( long long ) ( B[i].r + 0.5 )  ;
        }
    }
}

int a[maxn];
int ne[maxn];
int no[maxn];
int l[maxn],r[maxn];
int que[maxn];
void init(int n){
    int tot=0;
    for(int i=1;i<=n;i++){
        while(tot&&a[que[tot-1]]<=a[i]) tot--;
        if(tot==0) l[i]=0;
        else l[i]=que[tot-1];
        que[tot++]=i;
    }
    tot=0;
    for(int i=n;i>=1;i--){
        while(tot&&a[que[tot-1]]<=a[i]) tot--;
        if(tot==0) r[i]=n+1;
        else r[i]=que[tot-1];
        que[tot++]=i;
    }
}
int vis[maxn];
LL z[maxn];
vector<int>g;
int x[maxn<<2],y[maxn<<2];
LL q[maxn<<2];
int main()
{
    int n,t;
    cin>>t;
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        memset(vis,0,sizeof(vis));
        memset(z,0,sizeof(z));
        memset(no,0,sizeof(no));
        init(n);
        for(int i=n;i>=1;i--){
            ne[i]=i;
            if(no[a[i]]) ne[i]=no[a[i]];
            no[a[i]]=i;
        }
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            int cnt=0;
            int w=i;
            g.clear();
            int pre=l[i];
            while(ne[w]!=w&&ne[w]<=r[w]){
                x[cnt++]=w-pre;
                g.push_back(w);
                vis[w]=1;
                pre=w;
                w=ne[w];
            }
            g.push_back(w);
            vis[w]=1;
            x[cnt++]=w-pre;
            pre=r[w];
            int p=g.size();
            for(int j=p-1;j>=0;j--){
                y[p-1-j]=pre-g[j];
                pre=g[j];
            }
            w=1;
            while(w<=p) w=w*2;
            w=w*2;
            for(int j=p;j<=w;j++){
                x[j]=y[j]=0;
            }
            FFT::mul(x,y,q,w);
            for(int j=0;j<p;j++){
                z[p-j]+=q[j];
            }
        }
        LL ans=0;
        for(int i=1;i<=n;i++){
            ans+=i^z[i];
        }
        printf("%lld\n",ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值