Educational Codeforces Round 162 (Rated for Div. 2)(A~E)

因为是渡劫场,所以来水一篇题解(手速场,运气好,快速过了(a~e))

知乎blog传送门

A

代码

void solve () {
	ll n ; cin >> n ;
	vector < ll > a( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> a [ i ] ;
	}
	ll ans = 0 , res = 0, cnt = 0 ; bool flag = 0 ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		if ( !flag && a [ i ] == 1 ) {
			flag = 1 ;
		}
		if ( !flag ) continue ;
		if ( a [ i ] == 0 ) res += 1 ;
		else ans += res , res = 0 ;
	}
	cout << ans << endl ;
}

B

代码

void solve () {
	ll n , k ; cin >> n >> k ;
	vector < ll > a ( n ) , x ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> a [ i ] ;
	} 
	std::map < ll , ll > map ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> x [ i ] ; 
		map [ abs ( x [ i ] ) ] += a [ i ] ;
	}
	// vector < array < ll , 2 > > v ( map.begin () , map.end () ) ;
	ll ans = 0 , now = 0 , res = 0 ;
	for ( auto [ x , val ] : map ) {
		res += ( x - now ) * k ;
		now = x ;
		res -= val ;
		if ( res < 0 ) {
			cout << "NO" << endl ;
			return ;
		}
	}
	cout << "YES" << endl ;
}

C

可以证明,把 a a a 对应 1 1 1 的位置在 b b b 中对应 2 2 2 , a a a 大于 1 1 1 的数对应 b b b 中的 1 1 1 就行。如果对应区间长度为 1 1 1 ,显然无解,对应 b b b 对应区间小于等于 a a a 对应区间,显然有解

代码

void solve () {
	ll n , q ; cin >> n >> q ;
	vector < ll > a ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> a [ i ] ;
	}
	vector < ll > b ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		if ( a [ i ] == 1 ) b [ i ] = 2 ;
		else b [ i ] = 1 ;
	}
	vector < ll > sum1 ( n ) ;
	vector < ll > sum2 ( n ) ;
	sum1 [ 0 ] = a [ 0 ] , sum2 [ 0 ] = b [ 0 ] ;
	for ( int i = 1 ; i < n ; i += 1 ) {
		sum1 [ i ] = sum1 [ i - 1 ] + a [ i ] ;
		sum2 [ i ] = sum2 [ i - 1 ] + b [ i ] ;
	}
	while ( q-- ) {
		ll l , r ; cin >> l >> r ; -- l , -- r ;
		if ( l == r ) {
			cout << "NO" << endl ;
			continue ;
		}
		if ( sum2 [ r ] - ( l == 0 ? 0 : sum2 [ l - 1 ] ) <= sum1 [ r ] - ( l == 0 ? 0 : sum1 [ l - 1 ] ) ) {
			cout << "YES" << endl ;
		}
		else cout << "NO" << endl ;
	}
}

D

赛上卡了几分钟,就是假如对应 a a a 的一个位置,假如你小于左边或右边,显然为 1 1 1 ,大于左边(右边同理)时,你需要当前位置 i i i 从左边第一个数开始往左的找到第一个点 j j j ,使得 ∑ i t = j i − 1 a [ i t ] > a [ i ] \sum_{it=j}^{i-1} a [it]>a[i] it=ji1a[it]>a[i](先往下看),但是注意到假如你左边连续相等的话是不能相互吞并的,所以你需要维护一个第一个不与左边相等的数的位置的数组,这很简单,然后维护一下前缀和二分一下就能找到答案

void solve () {
	ll n ; cin >> n ; 
	vector < ll > a ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> a [ i ] ;
	}
	vector < ll > l ( n ) , r ( n ) , lf ( n ) , rf ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		r [ i ] = ( i == 0 ? 0 : r [ i - 1 ] ) + a [ i ] ;
		if ( i == 0 ) lf [ i ] = -1 ;
		else lf [ i ] = ( a [ i ] == a [ i - 1 ] ? lf [ i - 1 ] : i - 1 ) ;
	}
	for ( int i = n - 1 ; i >= 0 ; i -= 1 ) {
		l [ i ] = ( i == n - 1 ? 0 : l [ i + 1 ] ) + a [ i ] ;
		if ( i == n - 1 ) rf [ i ] = n ;
		else rf [ i ] = ( a [ i ] == a [ i + 1 ] ? rf [ i + 1 ] : i + 1 ) ;
	}
	vector < ll > ans ( n , -1 ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		if ( ( i != 0 && a [ i ] < a [ i - 1 ] ) || ( i != n - 1 && a [ i ] < a [ i + 1 ] ) ) {
			ans [ i ] = 1 ; continue ;
		}
		ll fa = ( i == 0 ? -1 : lf [ i - 1 ] ) ;
		auto it = upper_bound ( l.rbegin () + ( n - 1 ) - fa , l.rend () , l [ i ] + a [ i ] ) ;
		if ( it != l.rend () ) {
			if ( ans [ i ] == -1 ) {
				ans [ i ] = i - ( ( n - 1 ) - ( it - l.rbegin () ) ) ;
			}
		}
		fa = ( i == n - 1 ? n : rf [ i + 1 ] ) ;
		auto it2 = upper_bound ( r.begin () + fa , r.end () , r [ i ] + a [ i ] ) ;
		if ( it2 != r.end () ) {
			if ( ans [ i ] == -1 ) {
				ans [ i ] = it2 - r.begin () - i ;
			}
			else ans [ i ] = std::min ( ans [ i ] , it2 - r.begin () - i ) ;
		}
	}
	for ( int i = 0 ; i < n ; i += 1 ) {
		cout << ans [ i ] << ' ' ;
	}
	cout << endl ;
}

E

几乎和前几天abc压轴G题一模一样

我的abc题解

树上启发式合并,非常经典

看完之后看看我代码就行了

void solve () {
	ll n ; cin >> n ;
	vector < ll > a ( n ) ;
	for ( int i = 0 ; i < n ; i += 1 ) {
		cin >> a [ i ] ;
	}
	vector < vector < ll > > map ( n ) ;
	for ( int i = 1 ; i < n ; i += 1 ) {
		ll u , v ; cin >> u >> v ; -- u , -- v ;
		map [ u ].push_back ( v ) ;
		map [ v ].push_back ( u ) ;
	}
	ll ans = 0 ;
	auto dfs = [ & ] ( auto&& dfs , ll now , ll fa ) -> std::map < ll , ll > {
		std::map < ll , ll > f ;
		for ( auto here : map [ now ] ) {
			if ( here == fa ) continue ;
			std::map < ll, ll > s = move ( dfs ( dfs , here , now ) ) ;
			ans += s [ a [ now ] ] ;
			s [ a [ now ] ] = 0 ;
			if ( s.size () > f.size () ) swap ( f , s ) ;
			for ( auto [ x , sz ] : s ) {
				auto& fsz = f [ x ] ;
				ans += fsz * sz ;
				fsz += sz ;
			}
		}
		f [ a [ now ] ] = 1 ;
		return f ;
	};
	dfs ( dfs , 0 , 0 ) ;
	cout << ans << endl ;
}

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值