zoukankan      html  css  js  c++  java
  • [CF631E]Product Sum

    题目

    点这里看题目。

    分析

    设未交换时的结果为 (c) ,记 (s) 为前缀和数组。

    那么考虑将 (i) 交换到 (j) 之后( (j<i) ),交换的变化量为:

    [egin{aligned} &Delta=(s_i-s_j-A_i)+(j+1-i)A_i\ Rightarrow &Delta=(jA_i-s_j)+(s_i-iA_i) end{aligned} ]

    可以发现前面的括号内是关于 (j)(i) 的函数,且不看 (A_i) 则是 (j) 的一次函数。

    因此我们可以使用李超线段树维护 (0sim i-1) 的这些一次函数。当然,由于斜率单调,这里可以使用单调栈维护下凸包。

    反过来 (j>i) 的情况是类似的,化简的结果为:

    [Delta=(jA_i+s_j)+(-s_i-iA_i) ]

    类似维护即可。时间是 (O(nlog_2n))

    代码

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int MAXN = 2e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0; char s = getchar(); int f = 1;
    	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
    	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ) putchar( '-' ), x = -x;
    	if( 9 < x ) write( x / 10 );
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    template<typename _T>
    void swapp( _T &x, _T &y )
    {
    	_T t = x; x = y, y = t;
    }
    
    struct Linear
    {
    	LL k, b;
    	Linear() { k = b = 0; }
    	Linear( LL K, LL B ) { k = K, b = B; }
    	LL operator () ( const LL x ) const { return k * x + b; }
    };
    
    Linear f[MAXN], func[MAXN];
    
    LL su[MAXN], val[MAXN];
    int A[MAXN], pos[MAXN], coe[MAXN];
    int N, tot;
    
    void Build( const int l, const int r )
    {
    	if( l > r ) return ; 
    	int mid = l + r >> 1;
    	f[mid] = Linear( 0, -INF );
    	Build( l, mid - 1 );
    	Build( mid + 1, r );
    }
    
    void Update( const int l, const int r, Linear nw )
    {
    	if( l > r ) return ;
    	int mid = l + r >> 1;
    	if( f[mid]( val[mid] ) < nw( val[mid] ) ) swapp( f[mid], nw );
    	if( f[mid]( val[l] ) <= nw( val[l] ) ) Update( l, mid - 1, nw );
    	else Update( mid + 1, r, nw );
    }
    
    LL Query( const int l, const int r, const int p )
    {
    	if( l > r ) return -INF;
    	int mid = l + r >> 1; LL ret = f[mid]( val[p] );
    	if( p < mid ) ret = MAX( Query( l, mid - 1, p ), ret );
    	if( mid < p ) ret = MAX( Query( mid + 1, r, p ), ret );
    	return ret;
    }
    
    void Discrete()
    {
    	tot = 0; for( int i = 1 ; i <= N ; i ++ ) val[++ tot] = A[i];
    	sort( val + 1, val + 1 + tot ); tot = unique( val + 1, val + 1 + tot ) - val - 1;
    	for( int i = 1 ; i <= N ; i ++ ) pos[i] = lower_bound( val + 1, val + 1 + tot, A[i] ) - val;
    }
    
    int main()
    {
    	read( N ); LL ans = 0, base = 0;
    	for( int i = 1 ; i <= N ; i ++ ) read( A[i] ), coe[i] = i, base += 1ll * i * A[i];
    	
    	Discrete(), Build( 1, tot ), func[0] = Linear( 0, 0 ), Update( 1, tot, func[0] );
    	for( int i = 1 ; i <= N ; i ++ ) func[i] = Linear( i, - ( su[i] = su[i - 1] + A[i] ) );
    	for( int i = 1 ; i <= N ; i ++ ) ans = MAX( ans, Query( 1, tot, pos[i] ) + su[i] - 1ll * i * A[i] ), Update( 1, tot, func[i] );
    	Build( 1, tot ), func[N + 1] = Linear( N + 1, 0 ), Update( 1, tot, func[N + 1] );
    	for( int i = N ; i ; i -- ) func[i] = Linear( i, su[i] = su[i + 1] + A[i] );
    	for( int i = N ; i ; i -- ) ans = MAX( ans, Query( 1, tot, pos[i] ) - su[i] - 1ll * i * A[i] ), Update( 1, tot, func[i] );
    	
    	write( ans + base ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    Redis作者谈Redis应用场景(转)
    程序员必读书籍及导读指南(转)
    Python迭代器包itertools(转)
    Flash 0day漏洞(CVE-2018-4878)复现
    第二届“强网杯”全国网络安全挑战赛来袭——线上赛
    网站漏洞——文件判断函数的安全风险(实战篇)
    Android逆向进阶——让你自由自在脱壳的热身运动(dex篇)
    【python入门】之教你编写自动获取金币脚本
    Python大法之从火车余票查询到打造抢Supreme神器
    读DEDECMS找后台目录有感
  • 原文地址:https://www.cnblogs.com/crashed/p/14157117.html
Copyright © 2011-2022 走看看