点这里看题目。
首先需要弄清楚如何枚举 \(t\)。由于无论按键是否有效,播放器都会被重置状态。因此,某个按键是否有效仅仅取决于上一个按键与此的时间差和 \(t\) 的关系。那么我们就可以很好地用相邻差来划分 \(t\) 的阶段——有效的 \(t\) 的阶段只有 \(O(n)\) 个。枚举 \(t\) 并模拟。当我们求出 \(t_{\max}\) 之后,剩下的 \(V_2\) 是关于 \(V_1\) 的单调不降的函数,直接二分就好了,复杂度为 \(O(n^2)\)。
考虑加速枚举 \(t\) 的过程。实际上在某个确定的阶段中,我们仅仅想要知道是否存在 \(V_1\),使得最终计算出来的结果为 \(V_2\)——或者,我们可以构造一个函数 \(f_t(V_1)\),而我们只需要考察 \(V_2\) 是否在 \(V_1\) 之中。
没有操作的情况是 \(f(V_1)=V_1\),而有一个 +
的操作是 \(f(V_1)=\min\{V_{\max},V_1+1\}\),有一个 -
的操作是 \(f(V_1)=\max\{0,V_1-1\}\)。多次操作则是这样的基本函数的复合,而更一般的情况是,我们发现 \(f_t(V_1)\) 总可以被描述为 \(\min\{\max\{x+c,a\},b\}\),它的复合也可以比较容易地 \(O(1)\) 计算。
因此,我们的问题变成了——动态维护 \(O(n)\) 个函数的复合结果,并且需要支持将某一个函数重置为 \(f(V_1)=V_1\)。由于结合律,这是一个比较简单的、可以使用线段树维护的问题。总复杂度即为 \(O(n\log n)\)。
小结:
#include <cstdio> #include <utility> #include <algorithm> #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ ) #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- ) const int MAXN = 2e5 + 5; template<typename _T> void read( _T &x ) { x = 0; char s = getchar(); bool f = false; while( s < '0' || '9' < s ) { f = s == '-', s = getchar(); } while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); } if( f ) x = -x; } 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 MIN( const _T a, const _T b ) { return a < b ? a : b; } template<typename _T> _T MAX( const _T a, const _T b ) { return a > b ? a : b; } int Vmax; struct Func { int a, b, c; Func(): a( 0 ), b( Vmax ), c( 0 ) {} Func( int A, int B, int C ): a( A ), b( B ), c( C ) {} inline int operator () ( const int &x ) const { return MIN( MAX( x + c, a ), b ); } inline Func operator [] ( const Func &g ) const { return Func( ( * this ) ( g.a ), ( * this ) ( g.b ), c + g.c ); } }; typedef std :: pair<int, int> Event; Event eve[MAXN]; int tot = 0; Func tre[MAXN << 2]; int tim[MAXN]; bool swt[MAXN]; int N, V2; void Build( const int x, const int l, const int r ) { if( l == r ) { if( swt[l] ) tre[x] = Func( 0, Vmax, -1 ); else tre[x] = Func( 0, Vmax, 1 ); return ; } int mid = ( l + r ) >> 1; Build( x << 1, l, mid ); Build( x << 1 | 1, mid + 1, r ); tre[x] = tre[x << 1 | 1][tre[x << 1]]; } void Reset( const int x, const int l, const int r, const int p ) { if( l == r ) { tre[x] = Func(); return ; } int mid = ( l + r ) >> 1; if( p <= mid ) Reset( x << 1, l, mid, p ); else Reset( x << 1 | 1, mid + 1, r, p ); tre[x] = tre[x << 1 | 1][tre[x << 1]]; } int Solve() { int l = 0, r = Vmax, mid; while( l < r ) { mid = ( l + r + 1 ) >> 1; if( tre[1]( mid ) <= V2 ) l = mid; else r = mid - 1; } return l; } signed main() { read( N ), read( Vmax ), read( V2 ); rep( i, 1, N ) { char op[5]; scanf( "%s", op ), read( tim[i] ); swt[i] = op[0] == '-'; } Build( 1, 2, N ); if( tre[1]( 0 ) <= V2 && V2 <= tre[1]( Vmax ) ) return puts( "infinity" ), 0; rep( i, 1, N - 1 ) eve[++ tot] = Event( tim[i + 1] - tim[i], i + 1 ); std :: sort( eve + 1, eve + 1 + tot, [] ( const Event &a, const Event &b ) -> bool { return a.first > b.first; } ); for( int i = 1, j ; i <= tot ; i = j ) { for( j = i ; j <= tot && eve[j].first == eve[i].first ; ) Reset( 1, 2, N, eve[j ++].second ); if( tre[1]( 0 ) <= V2 && V2 <= tre[1]( Vmax ) ) { write( eve[i].first - 1 ), putchar( ' ' ); write( Solve() ), putchar( '\n' ); break; } } return 0; }