Educational Codeforces Round 105 (Rated for Div. 2)(题解ABC)

题目链接:Educational Codeforces Round 105 (Rated for Div. 2)

建议多看standing榜首几个大佬的代码,思路清晰也写的简洁。

A. ABC String


题意:给一个由A,B,C组成的字符串,用 ‘(’ 或者 ‘)’ 替换其中一种字母,要求相同字符替换后也必须相同,判断是否存在一种方案,使得替换后的括号串,符合日常运算写法的形式。

思路1:第一个字母必然时左括号,最后一个字母必然是右括号,剩下一个字母就只剩两种情况,枚举剩下字母的状态,再判断序列是否合法就行。

但个人更加推荐第二种思路,虽然程序计算量更大,但简单粗暴,对付水题这种方法思路更加简单,时间也够,也不用担心自己思路出错。

思路2:二进制枚举
ABC每个字符只有两种被替换后的状态,于是所有的情况就是 2 ∗ 2 ∗ 2 = 8 2*2*2=8 222=8种,二进制枚举所有状态即可。


思路2代码:

#include <bits/stdc++.h>
using namespace std;

bool check(string s1){
    int blance=0;
    for(auto c :s1){
        if(c=='(')blance++;
        else blance--;
        if(blance<0) return 0;
    }
    if(blance)return 0;
    return 1;
}

void solve(){
	string s;
    cin>>s;
    for(int mask=0;mask<8;mask++){//mask意为掩膜,代表分割后的结果
        string s1;
        for(auto c :s){//推荐这样遍历字符串,省手写时间
            if(mask&1<<(c-'A'))s1+='(';//注意位移运算优先级大于位运算
            else s1+=')';
        }
        if(check(s1)){
            cout<<"YES\n";
            return;
        }
    }
    cout<<"NO\n";
}

int main(){
    int T;
    cin>>T;
    while(T--){
 		solve();
    }
}

B. Berland Crossword


题意:有一个由 n ∗ n n*n nn的白色方块组成的矩阵,给出分别给出n,上,右,下,左边所需要涂黑的方块个数,判断是否能够完成涂色。

思路:判断涂色任务是否能够完成的关键,在于矩形四角是否涂色,每个角仅有两种状态,涂色和不涂色,总共 2 4 2^4 24种状态,二进制枚举即可。涂黑的角就在对应两邻边要求数量的基础上减去1即可。


#include <bits/stdc++.h>
using namespace std;


void solve(){
    int n,U,R,D,L,u,r,d,l;
    cin>>n>>U>>R>>D>>L;
    bool f=0;
    for(int mask=0;mask<16;mask++){
        u=r=d=l=0;
        if(mask&1)u++,r++;
        if(mask&2)r++,d++;
        if(mask&4)d++,l++;
        if(mask&8)l++,u++;

        if(u>U||U-u>n-2)continue;
        if(r>R||R-r>n-2)continue;
        if(d>D||D-d>n-2)continue;
        if(l>L||L-l>n-2)continue;

        f=1;
    }

    if(f)cout<<"YES\n";
    else cout<<"NO\n";
}


int main(){
    int T;
    cin>>T;
    while(T--){
        solve();
    }
}

C. 1D Sokoban


题意:1维推箱子游戏,不能穿过拉扯箱子,推的当前的箱子如果挨到后面的箱子,可以连着一起推,求最多能把多少箱子推到指定位置上。

思路:正负两边对称,于是只算一种情况的解法,两边结果相加就行,然后模拟推箱子的情况,计算答案,用lower_bounder,搜索下一个点的位置,避免超时。


#include<bits/stdc++.h> 
#include<vector> 
#include<set>
using namespace std;

int calc(vector<int> a,vector<int> b){
	int n=a.size(),m=b.size();
	vector<int>suf(n+1,0);
	set<int>pos( b.begin() , b.end() );
	for(int i=n-1;i>=0;i--){
		suf[i]=suf[i+1];
		if( pos.count(a[i]) )suf[i]++;	
	}//suf[i]表示推动第i个箱子时,在正确位置上的数量。 
	
	int ans=suf[0];//一个都不动的时候 
	for(int take=1;take<=n;take++){	//take表示第take-1个箱子堆积的长度 
		auto it=lower_bound( b.begin(), b.end() ,a[take-1]);
		if (it==b.end()) continue;
		
		int idx= it - b.begin();
		int LIM= 1e9+5;
		if(take<n)LIM =a[take]-1; 
		
		while(idx<m&&b[idx]<=LIM){//将长度为take的箱子,推到take+1的位置前的b处。 
			int idx1=lower_bound(b.begin(), b.end() ,b[idx]-take+1 )-b.begin();
			ans=max(ans,suf[take]+idx-idx1+1); 
			idx++;
		}		
	}
	return ans;
}


void solve(){
	int n,m,ans=0;
	cin>>n>>m;
	vector<int>a(n),b(m),a1,b1;
	for(int i=0;i<n;i++)cin>>a[i];
	for(int i=0;i<m;i++)cin>>b[i];
	for(auto it:a)if(it>0) a1.push_back(it);
	for(auto it:b)if(it>0) b1.push_back(it);
	ans+=calc(a1,b1);
	
	a1.clear();b1.clear();
	for(auto it:a)if(it<0) a1.push_back(-it);
	for(auto it:b)if(it<0) b1.push_back(-it);
	reverse(a1.begin(),a1.end()); 
	reverse(b1.begin(),b1.end());
	ans+=calc(a1,b1);
	cout<< ans << endl;
}

int main(){
	ios_base::sync_with_stdio(0);//cin记得关闭同步流不然会浪费很多额外时间
    cin.tie(nullptr);
	int t;		
	cin>>t;
	while(t--){
		solve();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值