Codeforces Round #712 (Div. 2) (题解)

传送门
在这里插入图片描述在这里插入图片描述题目大意:
给定一个字符串,你可以给任意位置插入一个‘a’,
如果可以使字符串不为回文串,那么输出YES并输出
任意满足的情况
如果不可以,输出NO

思路:
如果字符串全为a,则输出NO
否则输出YES.
从左到右直到第一个不为a找左边有多少个a,记为l,
从右到左直到第一个不为a找右边有多少个a,记为r
如果l == r ,则将a加在字符串末尾
否则,将a加在字符串a多的那一边

代码:

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

#define LL long long 
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

void slove()
{
    string s;
    cin >> s;
    bool ans = false;
    int left = 0,right = 0;
    for(int i = 0;i < s.length();++i){
        if(s[i] != 'a') {
            ans = true;
            left = i+1;
            break; 
        }
    }
    if(!ans) cout << "NO" << endl;
    else {
        for(int i = s.length()-1;i >= 0;--i){
            if(s[i] != 'a') {
                right = s.length() - i;
                break; 
            }
        }
        if(left == right) s+='a';
        else if(left > right) s = 'a' + s;
        else s = s + 'a';
        cout << "YES" << endl;
        cout << s << endl;
    }
}

int main()
{
    IO;
    int t;
    cin >> t;
    while(t--){
        slove();
    }
    return 0;
}

题目总结:
思维水题,确定思维证明无误后,再顺畅的敲代码,
这不仅是一种成功,更是一种享受

传送门
在这里插入图片描述在这里插入图片描述题目大意:
给定a,b两个字符串
如果a的前n个字符满足0的个数和1的个数相等
则可以将a的前n个字符0->1和1->0
可以进行任意此操作,判断是否可以将a变成b

思路:
从后往前,我们从第一个不相等的位置将a字符串前部翻转
翻转之后,接着往前找相等的位置将字符串a前部翻转
重复前两个操作,直到结束
注意特判结束的情况
主要记录判断每次字符串是否可以翻转

代码:

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

#define LL long long 
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

void slove()
{
    int n;
    cin >> n;
    string s1,s2;
    cin >> s1 >> s2;
    int l1=0,r1=0,l2=0,r2=0;
    for(int i = 0;i < s1.length();++i){
        if(s1[i] == '0') l1++;
        else r1++;
        if(s2[i] == '0') l2++;
        else r2++;
    }
    if(l1 != l2){
        cout << "NO" << endl;
        return ;
    }
    bool ans = false,sign = true;
    for(int i = s1.length()-1;i >= 0 && sign;--i){
        if(!ans){
            if(s1[i] == s2[i]){
                if(s1[i] == '0') l1--;
                else r1--;
            }
            else {
                ans = true;
                if(l1 == r1) {
                    if(s1[i] == '0') l1--;
                    else r1--;
                }
                else sign = false;
            }
        }
        else {
            if(s1[i] != s2[i]){
                if(s1[i] == '0') l1--;
                else r1--;
            }
            else {
                ans = false;
                if(l1 == r1) {
                    if(s1[i] == '0') l1--;
                    else r1--;
                }
                else sign = false;
            }
        }
    }
    if(sign) cout << "YES" << endl;
    else cout << "NO" << endl;
}

int main()
{
    IO;
    int t;
    cin >> t;
    while(t--){
        slove();
    }
    return 0;
}

题目总结:
思维中等题,从后往前遍历是一个比较常用的思路。
这个题虽然没有用到前缀和,但是和前缀和有一些相像的地方。
比如:记录从前到翻转位置0,1的数量

传送门
在这里插入图片描述在这里插入图片描述题目大意:
给定一个01串,
我们来构造左右括号的匹配情况,
如果可以出现两种左右括号情况
使得1对应的位置相等
使得0对应的位置不相等
那么输出YES并输出那两种情况
否则输出NO

思路:
如果0字符的个数为偶数或者第一个或最后一个字符为0则输出NO
否则输出YES
这时候我们确定了第一个位置和最后一个位置是1。
令它们分别为()
然后对于剩余1我们进行一左一右的编码,对于0进行一左一右编码
第二种情况1进行一左一右编码,对于0进行一右一左编码
那么它们一定满足上面的情况

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

#define LL long long 
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

void slove()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    int nm = 0;
    for(int i = 0;i < s.length();++i) if(s[i] == '0') nm++;
    if(nm%2 != 0 || s[n-1]=='0' || s[0]=='0') {
        cout << "NO" << endl;
        return ;
    }
    cout << "YES" << endl;
    bool l1=true,r1=true;
    cout << '(';
    for(int i = 1;i < s.length()-1;++i){
        if(s[i] == '1') {
            if(l1) cout << '(';
            else cout << ')';
            l1 = !l1;
        }
        else {
            if(r1) cout << '(';
            else cout << ')';
            r1 = !r1;
        }
    }
    cout << ')' << endl;
    l1=true,r1=false;
    cout << '(';
    for(int i = 1;i < s.length()-1;++i){
        if(s[i] == '1') {
            if(l1) cout << '(';
            else cout << ')';
            l1 = !l1;
        }
        else {
            if(r1) cout << '(';
            else cout << ')';
            r1 = !r1;
        }
    }
    cout << ')' << endl;
}

int main()
{
    IO;
    int t;
    cin >> t;
    while(t--){
        slove();
    }
    return 0;
}

题目总结:
思维拐弯题,如果我们注意力集中在一左一右的匹配那就进入死胡同了
这时候我们的思维指向10的区分处理,也就是“分治”思想,
那这个题就豁然开朗了,1处理自己的,0处理自己的
化繁为简,大道使然

传送门
在这里插入图片描述在这里插入图片描述在这里插入图片描述题目大意:
用不超过三种颜色填满n*n的格子使得相邻的格子颜色不同。
交互题,一个输出立马给出一个结果
Alice给出一个颜色,然后使用不是这个颜色的颜色去填空格
输出颜色和位置

思路:
我们用两个队列将所有格子空开,用1,2分别去填满其中一种再用3去填没满的队列。当其中一个队列填满剩下未填满的格子都是隔开的用3去填不会出现任何问题

#include<iostream>
#include<vector>
using namespace std;

#define IO ios::sync_with_stdio(0),cin.tie(0)
#define LL long long
LL n;
vector<LL> A,B;

void slove()
{
	cin >> n;
	for(int i = 0;i < n;++i){
		for(int j = 0;j < n;++j){
			if((i+j)%2 == 0)
				A.push_back(i*n+j);
			else 
				B.push_back(i*n+j);
		}
	}
	LL x = A.size();
	LL y = B.size();
	LL p = 0;
	LL q = 0;
	LL a;
	for(int i = 0;i < n*n;++i){
		cin >> a;
		if(p < x && q < y){
			if(a == 1){
				cout << 2 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
				q++;
			}
			else {
				cout << 1 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
				p++;
			}
		}
		else if(p == x){
			if(a == 2) {
				cout << 3 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
				q++;
			}
			else {
				cout << 2 << " " << B[q]/n+1 << " " << B[q]%n+1 << endl;
				q++;
			}
		}
		else {
			if(a == 1){
				cout << 3 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
				p++;
			}
			else {
				cout << 1 << " " << A[p]/n+1 << " " << A[p]%n+1 << endl;
				p++;
			}
		}
	}
}

int main()
{
	IO;
	slove();
}

题目总结:
第一次做交互题,没有接触经验,导致考虑的时候漏洞百出。
没有良好的思维变化。对于交互题可以理解成出错处理来思考。
例如队列填满了,填不了了就出错了,填副对角线,副对角线怎么填,用3来填。

传送门
在这里插入图片描述在这里插入图片描述题目大意:
每个城市有一个ai和ci
从第i个城市到第j个城市需要花费
max(a[j],a[i]-a[j])
问从第一个城市出发回到第一个城市的最小花费
旅行商问题

思路:
我们走一圈至少花费c[i]的总和
然后排序补齐a[j]-a[i]-c[i]的花费

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

#define LL long long
const int maxn = 1e5+5;
struct stu{
	LL l,r;
}a[maxn*2];

bool cmp(struct stu a,struct stu b)
{
	if(a.l == b.l) return a.r < b.r;
	else return a.l < b.l;
}

int main()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n;++i) cin >> a[i].l >> a[i].r;
	sort(a+1,a+n+1,cmp);
//	for(int i = 1;i <= n;++i) cout << a[i].l << " " <<  a[i].r << endl;
	LL sum = 0;
	for(int i = 1;i <= n;++i) sum+=a[i].r;
	LL naj = a[1].l+a[1].r;
	for(int i = 2;i <= n;++i){
		if(naj < a[i].l){
			sum += (a[i].l - naj);
		}
		naj = max(naj,a[i].l+a[i].r);
	}
	cout << sum << endl;
	return 0;
}

题目总结:
思维题转换题,要对于题意有一定的理解
大胆猜测,小心检验

传送门
在这里插入图片描述
在这里插入图片描述题目大意:
左边从小到大,右边从大到小
每行数据符合l[i],r[i]的位置上相同

思路:

无:

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

int n;
int a[200000+20],b[200000+20];
int ano[200000*2+20];
bool is[200000*2+20];
bool bad[200000*2+20];

pair<int,int> gao(int l,int r,int &val)
{
	val = !is[l];
	int l_,r_;
	l_ = l,r_ = ano[l];
	int prel=l,prer=ano[l];
	bad[ano[l]] = 1;
	r += 1;
	while(l < l_ || r > r_)
	{
		if(l < l_){
				while(l < l_){
					++l;
					if(!bad[l]){
						val += !is[l];
						if(ano[l] > prer){
							return make_pair(-1,-1);
						}
						bad[ano[l]] = 1;
						prer = ano[l];
					}
				}
			if(prer < l_) return make_pair(-1,-1);
			r_ = prer;
		}
		else{
			while(r > r_){
				--r;
				if(!bad[r]){
					val += !is[r];
					if(ano[r] < prel){
						return make_pair(-1,-1);
					}
					bad[ano[r]] = 1;
					prel = ano[r];
				}
				if(prel > r_)
					return make_pair(-1,-1);
				l_ = prel;
			}
		}
	}
	return make_pair(l_,r_);
}

int slove(int A,int B)
{
	if(A > B) return 0;
	int z = 0;
	pair<int,int> seg = gao(A,B,z);
	if(seg.first == -1) return -1;
	int cnt = B-seg.second+1+seg.first-A+1;
	int tmp = slove(seg.first+1,seg.second-1);
	if(tmp == -1) return -1;
	return tmp+min(cnt/2-z,z);
}

int main()
{
	cin >> n;
	for(int i = 1;i <= n;++i){
		cin >> a[i] >> b[i];
		ano[a[i]] = b[i];
		ano[b[i]] = a[i];
		is[a[i]] = 1;
	}
	cout << slove(1,n+n) << endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值