zoukankan      html  css  js  c++  java
  • 「雅礼集训 2018 Day10」贪玩蓝月

    题目

    点这里看题目。

    分析

    离线的话,我们显然可以 线段树分治 + DP ,时间复杂度大概是 (O(mlog_2m+mp))

    不过,既然题目明确要求在线,却还不开强制在线,我们就应该去思考一下在线算法。

    显然我们需要一个 DP 去维护答案,这里不再赘述。

    考虑我们直接处理的难点之一是双端队列两段可操作,而一端可操作的结构,栈,就可以简单地维护 DP 。因此,我们考虑将双端队列拆成两栈分别维护左端和右端

    有了这个思路,剩下的都比较简单了。插入操作可以直接维护 DP 数组。删除操作可以把栈顶的 DP 数组清空。查询的时候,我们枚举一端的 DP 值 (dpl(i)) ,此时对应可用的 (dpr) 的值必然是一段区间,我们可以考虑使用单调队列之类的数据结构维护一下。

    插入、查询都可以做到 (O(p)) 。删除时,如果一端的栈已经被删空了,我们需要在另一端的栈里打上标记,在之后对两个栈进行均分重构

    时间复杂度是 ...... (O(? imes p))

    代码

    #include <cstdio>
    #include <cstring>
    
    typedef long long LL;
    
    const LL INF = 1e10;
    const int MAXN = 5e4 + 5, MAXP = 505;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && 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 ) + 1; }
    	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;
    }
    
    LL DPL[MAXN][MAXP], DPR[MAXN][MAXP];
    
    LL f[MAXP << 1];
    int q[MAXP];
    
    int stkL[MAXN], stkR[MAXN];
    int tmp[MAXN];
    
    int w[MAXN], v[MAXN];
    int N, P, topL, topR, butL, butR;
    
    void rebuild();
    void upt( LL &x, const LL v ) { x = MAX( x, v ); }
    int fix( const int a ) { return ( a % P + P ) % P; }
    
    void popL() 
    { 
    	if( ! topL ) { butR ++; return ; }
    	topL --; 
    	if( ! topL ) rebuild(); 
    }
    
    void popR() 
    { 
    	if( ! topR ) { butL ++; return ; }
    	topR --; 
    	if( ! topR ) rebuild(); 
    }
    
    void insertL( const int id )
    {
    	w[id] %= P, stkL[++ topL] = id;
    	for( int i = 0 ; i < P ; i ++ ) DPL[topL][i] = -INF;
    	for( int i = 0 ; i < P ; i ++ ) 
    		upt( DPL[topL][i], DPL[topL - 1][i] ),
    		upt( DPL[topL][( i + w[id] ) % P], DPL[topL - 1][i] + v[id] );
    }
    
    void insertR( const int id )
    {
    	w[id] %= P, stkR[++ topR] = id;
    	for( int i = 0 ; i < P ; i ++ ) DPR[topR][i] = -INF;
    	for( int i = 0 ; i < P ; i ++ ) 
    		upt( DPR[topR][i], DPR[topR - 1][i] ),
    		upt( DPR[topR][( i + w[id] ) % P], DPR[topR - 1][i] + v[id] );	
    }
    
    void rebuild()
    {
    	int siz = 0;
    	for( int i = topL ; i > butL ; i -- ) tmp[++ siz] = stkL[topL];
    	for( int i = butR + 1 ; i <= topR ; i ++ ) tmp[++ siz] = stkR[i];
    	butL = butR = topL = topR = 0; 
    	int mid = siz >> 1;
    	for( int i = mid ; i ; i -- ) insertL( tmp[i] );
    	for( int i = mid + 1 ; i <= siz ; i ++ ) insertR( tmp[i] ); 
    }
    
    LL query()
    {
    	if( butL || butR ) rebuild();
    	int L, R;
    	LL ans = -INF;
    	int h = 1, t = 0, r = 0;
    	read( L ), read( R );
    	for( int i = 0 ; i < P ; i ++ ) f[i] = f[i + P] = DPR[topR][i];
    	for( int i = L ; ~ i ; i -- )
    	{
    		for( ; r <= fix( R - i ) ; r ++ )
    		{
    			while( h <= t && f[q[t]] <= f[r] ) t --;
    			q[++ t] = r;
    		}
    		while( h <= t && q[h] < L - i ) h ++;
    		ans = MAX( ans, f[q[h]] + DPL[topL][i] );
    	}
    	r = 0;
    	for( int i = P - 1 ; i > L ; i -- )
    	{
    		for( ; r <= R - i + P ; r ++ )
    		{
    			while( h <= t && f[q[t]] <= f[r] ) t --;
    			q[++ t] = r;
    		}
    		while( h <= t && q[h] < L - i + P ) h ++;
    		ans = MAX( ans, f[q[h]] + DPL[topL][i] );
    		
    	}
    	return ans < 0 ? -1 : ans;
    }
    
    int main()
    {
    	int qwq;
    	read( qwq );	
    	char op[10];
    	read( N ), read( P );
    	for( int i = 1 ; i < P ; i ++ )
    		DPL[0][i] = DPR[0][i] = -INF;
    	for( int cas = 1 ; cas <= N ; cas ++ )
    	{
    		scanf( "%s", op );
    		if( ! strcmp( op, "IF" ) ) read( w[cas] ), read( v[cas] ), 
    		insertL( cas ); 
    		if( ! strcmp( op, "IG" ) ) read( w[cas] ), read( v[cas] ), 
    		insertR( cas );
    		if( ! strcmp( op, "DF" ) ) popL();
    		if( ! strcmp( op, "DG" ) ) popR();
    		if( ! strcmp( op, "QU" ) ) write( query() ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java实现各种内部排序算法
    Java实现堆排序(大根堆)
    Java对象的序列化和反序列化
    Java实现链式存储的二叉查找树(递归方法)
    337. House Robber III(包含I和II)
    318. Maximum Product of Word Lengths
    114. Flatten Binary Tree to Linked List
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    96. Unique Binary Search Trees(I 和 II)
  • 原文地址:https://www.cnblogs.com/crashed/p/13463354.html
Copyright © 2011-2022 走看看