【玲珑杯】1048 - Best substring【manacher+分治维护凸壳】

2 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:【玲珑杯】1048 - Best substring

wa了一辈子,最后发现是利用归并排序后的退栈策略错了。应该是判栈顶和当前元素的关系,然而我偷懒只判了相邻两个元素的关系,gg。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 200005 ;

struct Line {
    LL k , b ;
    Line () {}
    Line ( LL k , LL b ) : k ( k ) , b ( b ) {}
    bool operator < ( const Line& a ) const {
        return k != a.k ? k < a.k : b < a.b ;
    }
    LL f ( int x ) {
        return k * x + b ;
    }
} ;

char Ma[MAXN << 1] ;
int R[MAXN << 1] ;
Line a[MAXN] ;
LL sum[MAXN] ;
LL val[MAXN] ;
LL tot[MAXN] ;
char s[MAXN] ;
int id[MAXN] ;
int c[MAXN] ;
int S[MAXN] ;
LL ans ;
int n ;

int check ( int i , int j , int k ) {
    return ( double ) ( a[i].b - a[j].b ) / ( a[j].k - a[i].k ) >= ( double ) ( a[i].b - a[k].b ) / ( a[k].k - a[i].k ) ;
}

void merge ( int a[] , int n , int b[] , int m ) {
    int i = 0 , j = 0 , k = 0 , t = 0 ;
    while ( i < n && j < m ) c[k ++] = sum[a[i]] < sum[b[j]] ? a[i ++] : b[j ++] ;
    while ( i < n ) c[k ++] = a[i ++] ;
    while ( j < m ) c[k ++] = b[j ++] ;
    while ( t < n + m ) a[t] = c[t] , t ++ ;
}

void dfs ( int l , int r ) {
    if ( l == r ) return ;
    int m = l + r >> 1 ;
    dfs ( l , m ) ;
    dfs ( m + 1 , r ) ;
    int cnt = 0 , t = 0 ;
    tot[m] = 0 ;
    for ( int i = m + 1 ; i <= r ; ++ i ) {
        tot[i] = tot[i - 1] + ( i - m ) * val[i] ;
    }
    for ( int i = m + 1 ; i <= r ; ++ i ) {
        a[++ cnt] = Line ( sum[id[i]] - sum[m] , tot[id[i]] ) ;
    }
    for ( int i = 1 ; i <= cnt ; ++ i ) {
        while ( t && a[S[t]].k == a[i].k && a[S[t]].b < a[i].b ) -- t ;
        while ( t > 1 && check ( S[t - 1] , S[t] , i ) ) -- t ;
        S[++ t] = i ;
    }
    LL res = 0 ;
    for ( int i = m , j = 1 , k = 1 ; i >= l ; -- i , ++ j ) {
        res += sum[m] - sum[i - 1] ;
        while ( k < t && a[S[k]].f ( j ) < a[S[k + 1]].f ( j ) ) ++ k ;
        ans = max ( ans , res + a[S[k]].f ( j ) ) ;
    }
    merge ( id + l , m - l + 1 , id + m + 1 , r - m ) ;
}

void manacher ( char s[] , int n ) {
    int l = 0 ;
    Ma[l ++] = '$' ;
    Ma[l ++] = '#' ;
    for ( int i = 0 ; i < n ; ++ i ) {
        Ma[l ++] = s[i] ;
        Ma[l ++] = '#' ;
    }
    Ma[l] = 0 ;
    for ( int i = 0 , mx = 0 , id = 0 ; i < l ; ++ i ) {
        R[i] = mx > i ? min ( R[2 * id - i] , mx - i ) : 1 ;
        while ( Ma[i + R[i]] == Ma[i - R[i]] ) R[i] ++ ;
        if ( i + R[i] > mx ) mx = i + R[i] , id = i ;
    }
}

void solve () {
    scanf ( "%d%s" , &n , s ) ;
    manacher ( s , n ) ;
    ans = 0 ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        val[i] = R[i * 2] - 1 ;
        if ( i % 2 == 0 ) val[i] = -val[i] ;
        sum[i] = sum[i - 1] + val[i] ;
        ans = max ( ans , val[i] ) ;
        id[i] = i ;
    }
    dfs ( 1 , n ) ;
    printf ( "%lld\n" , ans ) ;
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    while ( T -- ) solve () ;
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值