Educational Codeforces Round 53 (Rated for Div. 2) A 思维 B模拟 C二分 +尺取 D暴力 E数位dp+二进制压缩

本文深入解析了五道编程挑战题目,涵盖字符串处理、数组操作、数学算法、动态规划和数位DP等核心编程技能。通过具体代码实现,详细阐述了解题思路,适合初学者和竞赛选手参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A
思路:找出最简单的2个长度的情况就行。
Code:

#include <bits/stdc++.h>
using namespace std;
int main(){
	string s ; 
	int n ; 
	cin >> n ;
	cin >> s ;  
	for( int i = 0 ; i < n - 1 ; i++ ){
		if( s[i] != s[i+1] ){
			cout << "YES" << endl;
			cout << s[i] << s[i+1] << endl ; 
			return 0 ; 
		}
	}
	cout << "NO" << endl;
	return 0 ; 
}

B
思路:跟着模拟就行了。
Code:

#include <bits/stdc++.h>
using namespace std;
const int AX = 2e5 + 66 ; 
int a[AX] ;
int b[AX] ;
int vis[AX] ; 
int main(){
	int n ;
	cin >> n ;
	for( int i = 0 ; i < n ; i++ ){
		cin >> a[i] ; 
	}
	for( int i = 0 ; i < n ; i++ ){
		cin >> b[i] ; 
	}
	int tot = 0 ; 
	int cnt = 0 ; 
	for( int i = 0 ; i < n ; i++ ){
		if( vis[b[tot]] ){
			cout << 0 << ' ' ; tot ++ ; i--; continue ; 
		}
		vis[a[i]] = 1; 
		if( b[tot] != a[i] ){
			cnt ++ ; 
		}else{
			cout << cnt + 1 << ' ' ;
			cnt = 0 ; 
			tot ++ ; 
		}
	}
	if( cnt ){
		cout << cnt << ' ' ;
		tot ++ ;
		cnt = 0 ; 
	}
	if( tot < n ){
		for( int i = tot ; i < n ; i++ ){
			cout << 0 << ' ' ; 
		}
	}
	cout << endl;
	return 0 ; 
}

C
题意:给出一串操作,从(0,0)走到x,y,问修改最小的区间长度(修改首尾距离),使得能走到(ex,ey)。
思路:二分区间长度,然后尺取法判断小于等于这个区间的修改是否能够满足,这部分我是这样处理的:先取消尺取过程范围内的操作,因为区间内可以随意修改,然后判断区间长度len能否满足从x,y最小步数走到ex,ey,并且剩余长度为偶数(抵消)。
Code:

#include <bits/stdc++.h>
using namespace std ;
const int AX = 2e5 + 66 ;
char s[AX] ;
int ex , ey ; 
int n ; 
int x , y ; 
int cal( int x , int y ){
	if( ( x <= 0 && y <= 0 ) || ( x >= 0 && y >= 0 ) ) return abs(abs(x)-abs(y)) ; 
	if( x < 0 && y > 0 ) return abs(x) + y ;
	if( x > 0 && y < 0 ) return abs(y) + x ; 
}
bool solve( int mid ){
	int st = 0 , e = 0 ;
	int n_x = x , n_y = y ; 
	int len = 0 ; 
	while( st <= e ){
		while( e < n && len < mid ){
			if( s[e] == 'U' ) n_y -- ; 
			if( s[e] == 'D' ) n_y ++ ; 
			if( s[e] == 'L' ) n_x ++ ;
			if( s[e] == 'R' ) n_x -- ; 
			len ++ ; 
			int d_x = cal( ex , n_x ) ;
			int d_y = cal( ey , n_y ) ; 
			if( len >= d_x + d_y && ( len - d_x - d_y ) % 2 == 0 ) return true ;
			e ++ ; 
		}
		if( s[st] == 'U' ) n_y ++ ; 
		if( s[st] == 'D' ) n_y -- ; 
		if( s[st] == 'L' ) n_x -- ;
		if( s[st] == 'R' ) n_x ++ ; 
		st ++ ; 
		len -- ; 
	}	 
	return false ; 
}
int main(){
	scanf("%d%s",&n,s) ; 
	scanf("%d%d",&ex,&ey) ;  
	if( n < abs(ex) + abs(ey) ){
		return 0*printf("-1\n");
	}else{
		x = 0 , y = 0 ; 
		for( int i = 0 ;  i < n ; i ++ ) {
			if( s[i] == 'U' ) y ++ ; 
			if( s[i] == 'D' ) y -- ; 
			if( s[i] == 'L' ) x -- ;
			if( s[i] == 'R' ) x ++ ; 
		}
		if( x == ex && y == ey ) return 0*printf("0\n");
		int l = 0 , r = n ; 
		int res = n + 1 ;
		while( l <= r ){
			int mid = ( l + r ) >> 1 ;
			if( solve(mid) ){
				res = mid ;
				r = mid - 1 ; 
			}else{
				l = mid + 1 ; 
			}
		}
		if( res == n + 1 ) printf("-1\n");
		else printf("%d\n",res);
	}
	return 0 ;
}

D
思路:暴力,
Code:

#include <bits/stdc++.h>
#define LL long long 
using namespace std ;
const int AX = 2e5 + 666 ; 
int a[AX] ;
int vis[AX] ;
int main(){
	int n ;
	LL T ;
	cin >> n >> T ; 
	LL sum = 0LL ; 
	for( int i = 0 ; i < n ; i++ ){
		cin >> a[i] ; 
		sum += a[i] ; 
	}
	LL res = 0LL ;
	int num = n ; 
	while( true ){
		if( !num || !T ) break ; 
		if( T >= sum ){
			LL tmp = T / sum ; 
			T -= tmp * sum ;
			res += tmp * num ;  
		}else{
			for( int i = 0 ; i < n ; i++ ){
				if( vis[i] ) continue ; 
				if( T >= a[i] ){
					T -= a[i] ;
					res ++ ;
				}else{
					sum -= a[i] ; 
					vis[i] = 1 ; 
					num -- ; 
				}
			}
		}
	}
	cout << res << endl; 
	return 0 ; 
}

E
题意:求L到R范围内数字中,出现不同数字(0-9)个数<=k的数字(L-R)之和。
思路:数位dp, dp[i][j] 记录到i位 10个数字哪个数字出现过的状态,用二进制记录。
Code:

#include <bits/stdc++.h>
#define LL long long 
using namespace std; 
const int AX = 1e2 + 6 ;
const int MOD = 998244353 ;
int a[AX] ; 
LL l , r ;
int k ; 
struct Node{
	LL num ; 
	LL sum ; 	
	Node(){
		num = -1 ; 
		sum = 0 ; 
	}
	Node( LL num , LL sum ):num(num),sum(sum){}
}dp[AX][1050] ;
LL c[AX] ;  
Node dfs( int pos , int sta , bool lim ){
	if( pos == -1 ) return Node( 1 , 0 ) ;
	if( !lim && ~dp[pos][sta].num ) return dp[pos][sta] ;
	Node ans = Node( 0 , 0 ) ; 
	int up = lim ? a[pos] : 9 ;
	for( int i = 0 ; i <= up ; i++ ){
		int nowsta = 0 ;
		if( !sta && !i ){
			nowsta = 0 ;
		}else nowsta = sta | (1<<i) ; 
		if( __builtin_popcount(nowsta) > k ) continue ; 
		Node tmp = dfs( pos - 1 , nowsta , lim && i == a[pos] ) ;
		ans.num = ( ans.num + tmp.num ) % MOD ;
		ans.sum = ( ans.sum + tmp.sum + 1LL * tmp.num * c[pos] % MOD * i % MOD ) % MOD ;
	} 
	if( !lim ) dp[pos][sta] = ans ; 
	return ans ; 
}
void init(){
	c[0] = 1;
	for( int i = 1 ; i < 20 ; i++ ){
		c[i] = (c[i-1]*10) % MOD ;
	}
}
LL solve( LL x ){
	int tot = 0 ;
	while( x ){
		a[tot++] = x % 10 ; 
		x /= 10 ;  
	} 
	return dfs( tot - 1 , 0 , true ).sum ; 
}
int main(){
	init() ; 
	cin >> l >> r >> k ; 
	cout << ( solve(r) - solve(l-1) + MOD ) % MOD ;
	return 0 ; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值