2023.5.25~5.29codeforeces训练记录

题目一:C - Hamiltonian Wall

大意:给定2xN的矩阵,矩阵中只有'B','W',现在问能不能一次性连续的通过B且不经过W。

思路:模拟。显然,当从左边开始,若一列全为W则可以从下一列开始走,若全为B,则可以从下一列的任一行走,当遇到第一个有B和W的列时,才决定走的行是第1还是2行,然后遍历下一列,若下一列的该行为W则无法到达,反之能继续进行。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <iomanip>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e5+10;
char g[2][N] ;

int main()
{
	int T ;cin >>T;
	while( T--){
		//cout<<"_---";
		int n ;
		cin >> n ; 
		int Bcnt = 0 ;
		for(int i =0 ; i< 2 ; ++i)
			for(int j = 0 ; j < n ; ++j){
				cin >>g[i][j] ;
				if( g[i][j] == 'B') ++Bcnt; 
			}
		int cur_row = -1 ,sum = 0; 
		int i = 0 ;
		for(; i <n; ++i) if( g[0][i] != 'W' || g[1][i] !='W') break;
		for( ; i < n ; ++i){
			if( g[0][i] == 'B' && g[1][i] == 'B'){
				sum += 2 ; 
				if( cur_row != -1){
					if( cur_row ) cur_row =  0;
					else cur_row = 1;
				} 
				continue;
			}
			if( g[0][i] == 'W' && g[1][i] =='W') break;
			if( cur_row == -1){
				if( g[0][i] == 'B')  cur_row = 0 ;
					else cur_row = 1;
				
			}else {
				if( g[cur_row][i] =='W') {
					break;
				} 
			}
			++sum ; 
			
		}
		if( sum == Bcnt) cout<<"YES"<<endl;
			else cout<<"NO" <<endl;
	}
	 
	
    return 0 ;
}

问题二:C - Best Binary String

大意:给定一个只含有0,1,?的n长度数组a,一次操作可以对选定一个区间[L,R]翻转,现在需要你对?填补为0,1,使得得到的数组a,在经过最少次翻转就能成为升序数组。

思路:模拟。显然,最左边填0,最右边填1能够最快减少翻转的数组长度,故初始设L指针的符号为0,R指针符号为1。然后都向中间移动,当遇到?时,将?改为指针对应的符号,当遇到与指针符号不同的符号时,将指针变为该符号。直至两个指针相遇。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <iomanip>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;

int main()
{
	int T ;cin >>T;
	while( T--){
		string s ;
		cin >>s ; 
		int n =s.size() ; 
		int l =  0 , r= n -1 ;
		char lc = '0' , rc = '1' ;
		while( l <= r ){
			while(  l <= r  ){
				if( s[l] == lc) ++l;
				else if( s[l] == '?') s[l] = lc;
				else  {
					if( lc =='0') lc = '1';
					else lc = '0' ;
				}
			}
			while( l<=r) {
				if( s[r] ==rc) --r;
				else if( s[r] =='?') s[r]  =rc;
				else {
					if( rc == '0') rc ='1' ;
					else rc = '0' ;
				}
			}
		}
		cout<< s <<endl;
	}
	 
	
    return 0 ;
}

问题三:D - Bracket Coloring

大意:自行翻译。

思路:如下

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <iomanip>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e5+10 ;
int n ;
int id[N] ;
int main()
{

	int T; cin>>T;
	while( T--){
		int n ;cin >> n ;
		string s; cin >> s; 
		int sum = 0 ;
		for(int i = 0 ; i < s.size() ; ++i){
			if( s[i] =='(') sum ++ ;
			else sum--;
			if( sum > 0 ) id[i]  = 1;
			else if( sum<  0) id[i] =2;
			else id[i] = id[i-1];
		}
		if( sum){
			cout<<-1<<endl; continue; 
		}
		int t = 2;
		int type = 1;
		for(int i =0 ; i < n ; ++i) type = max( type , id[i]) ,t&=id[i] ;
		if( t ==2) type=1;
		cout<<type<<endl;
		for(int j =0; j< n; ++j)
			if( t==2 && type==1) cout<<1<<" ";
			else cout<<id[j] <<" " ;
		cout<<endl;
	}
	
    return 0 ;
}

问题四:D - Balanced Ternary String

大意:n =3k的字符串,只有0,1,2,请你用最少的修改次数修改字符串为各字符数量都是n/3,且字典序最小。

思路:遍历检索各元素存在数量。用prev表示某个位置前面某个字符的数量。显然,若某字符数量小于等于n/3,则无需修改。当大于n/3时,先判断该字符是否已经存在n/3个,若已存在,则无论如何,都需要找到最小的字符数量小于n/3的字符替换该位置,若小于n/3个,则先判断是否有比这个字符小的的字符的数量小于n/3,如果有则直接修改;没有的话则往下走。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <deque>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef  long long LL;
typedef pair<int,int> PII;
const int N = 4e5+10 ;

int h[N] , e[N]  ,ne[N],w[N] ,idx;
PII a[N ] ;

int main()
{
	int T ;T=1;
	while(T--){
		int n ;string s;
		cin >> n>>s;
		int cur[3] = {0} ;
		int k  =n/3;
		for(int i =0 ; i< s.size() ; ++i ){
			cur[s[i]-'0'] ++ ;
		}
		int prev[3] = {0} ;
		for(int i =0 ; i < s.size() ; ++i){
			if( cur[s[i] -'0'] > k ){
				if( prev[s[i] -'0'] == k){
					char ch = s[i] ;
					for( ; ch<='2' ;++ch) if( cur[ ch -'0'] <  k) break;
					cur[ ch-'0'] ++ ; cur[ s[i]-'0'] --;
					s[i] = ch ;   prev[ch-'0'] ++ ; 
				}else  {
					char ch = '0' ;
					for( ; ch< s[i] ;++ch) if( cur[ch-'0'] < k ) break;
					if( ch < s[i]){
						cur[ ch-'0'] ++ ; cur[s[i]-'0']--;
						s[i] =ch; prev[ch -'0'] ++ ;
					}else prev[ s[i]-'0'] ++;
				}
			}else prev[ s[i] -'0'] ++ ;
		}
		cout<<s<<endl;
	}

    return 0 ;
}

问题五:C - Copil Copac Draws Trees

大意:给定一个n节点的树和n-1条边,有一个算法,先画点1,  然后按边的输入次序,若一个点已经画好了,则画另一个点, 当进行完一轮,有点没画则继续按边的输入次序检索直至全部点画完。

思路:对每个无向边进行编号,然后从1开始dfs, 假设t已经画好,有边e1 = (t,u) ,e2 = (v,u),若 e1的编号小于e2,则v需要的次数和u相同,反之,v需要的次数比u大1。最后取最大值即可。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <deque>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef  long long LL;
typedef pair<int,int> PII;
const int N = 4e5+10 ;

int h[N] , e[N]  ,ne[N],w[N] ,idx;
int dist[N] ;
map< PII,int > pos;
bool st[N] ;

void add( int a, int b){
	e[idx]= b, ne[idx] =h[a] ,h[a] =idx++ ;
}



void dfs( int u ,int fa )
{
//	cout<<u <<"  --" <<dist[u] <<endl;
	for(int i =h[u] ;~i ; i =ne[i]){
		int j=e[i] ;
		if(  j ==fa ) continue;
		if( pos[{u,j}] > pos[{fa,u}]) dist[j] = dist[u];
		else dist[j] = dist[u] +1; 
		dfs( j ,u) ;
	}
}

int main()
{
	int T ;cin >>T;
	while(T--){
		int n;
		cin >> n ;
		memset( h ,-1, sizeof h ) ;idx= 0 ; 
		memset( st,false, sizeof st )  ;
		pos.clear() ;
		dist[1] =1;
		for(int i =1; i < n ; ++i){
			int a,b;
			cin >>a >>b;
			add(a,b) ;add(b,a) ;
			pos[{a,b}] =pos[ {b,a}] = i ;
		}
		dfs( 1 ,-1) ;
		int res= 0;
		for(int i=1; i<=n; ++i) res= max(res, dist[i]) ;
		cout<< res <<endl;
	}

    return 0 ;
}

问题六:C - Keshi in Search of AmShZ

大意:一个有向图,编号1~n。一次操作可往附近的节点跳,或者删除一条边。从1出发,假设每次移动都是往最糟糕的情况走,问至少操作多少次才能到达n。(可能存在重边)

思路:从n开始建立反向边。显然n只需0步,从(u,n)需要u的出度- u到除n顶点的边数+1。从n开始dfs即可。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <iomanip>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e5+10 ;

int h[N] , ne[N] ,e[N] ,idx;
int deg[N] , n , m  ;
int dist[N] ; 
bool st[N] ;
void add( int a ,int b ){
	e[idx] =b, ne[idx] = h[a] ,h[a] = idx++ ;
}

void dijskra( )
{
	memset( dist, 0x3f , sizeof dist) ;
	memset( st ,false, sizeof st) ; 
	priority_queue< PII , vector<PII> , greater<PII> > heap;
	dist[n]= 0 ; 
	heap.push({  0  , n }) ;
	while( heap.size()){
		auto t= heap.top(); heap.pop() ;
		int ver= t.y , distance =  t.x;
		//cout<<ver<<" " ;
		if( st[ver]  ) continue;
		st[ver] = true;
		for(int i = h[ver] ; ~i; i= ne[i]){
			int j =e[i] ;
			if( dist[j] > dist[ver] + deg[j]){
				dist[j] = dist[ver] + deg[j] ;
				heap.push( {dist[j] , j}) ;
			}
			deg[j] --;
		}
	}
}


int main()
{

	int T; T=1;
	while( T--){
		cin >> n >> m;
		memset(h , -1, sizeof h ) ;idx= 0 ; 
		while( m --){
			int a,b;
			cin >>a >>b ;
			add( b,a) ; 
			deg[a]++;
		}
		dijskra( ) ; 
		cout<< dist[1] <<endl ;
		
	}
	
    return 0 ;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值