大意:给定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 ;
}
大意:给定一个只含有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 ;
}
大意:自行翻译。
思路:如下
代码:
#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 ;
}