Codeforce Round 712 Div2
A. Deja Vu
题目链接
题目大意:
给定一个字符串,判断能否在这个字符串的某一个位置加入一个字符 ‘a’ 使得该字符串变成非回文串,输出 “YES” 或 “No”。
解题思路:
首先可得全由 a 组成的字符串必然不能满足条件,那么对于不全为 a 的串,若是回文的则可以直接加到字符串头部(反证法若加到头部不满足,那么递推可知该字符串全为 a ),对于非回文的则在开头与末尾各自判断一次,输出可能的结果即可。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef pair<int, int> PII;
const int N=3e5+10;
int q[N];
char s[N];
typedef long long ll;
int main()
{
int t;
cin >> t;
while(t--){
memset(s, 0, sizeof s);
cin >> s + 1;
int num = 0;
bool can = 0;
for (int i = 1; s[i] != '\0';i++){
num++;
if(s[i]!='a'){
can = 1;
}
}
if(!can){
puts("NO");
continue;
}
bool jug = true;
for (int i = 1, j = num; i <= j;i++,j--){
if(s[i]!=s[j]){
jug = false;
}
}
if(jug){
puts("Yes");
printf("a");
for (int i = 1; s[i] != '\0';i++){
printf("%c", s[i]);
}
printf("\n");
}
else{
s[0] = 'a', s[num+1]='a';
bool ans1 = 0, ans2 = 0;
for (int i = 0, j = num; i <= j;i++,j--){
if(s[i]!=s[j]){
ans1 = 1;
break;
}
}
for (int i = 1, j = num + 1; i <= j;i++,j--){
if(s[i]!=s[j]){
ans2 = 1;
break;
}
}
if(!ans1&&!ans2){
puts("No");
}
else{
puts("Yes");
if(ans1){
for (int i = 0; i <= num;i++){
printf("%c", s[i]);
}
printf("\n");
continue;
}
if(ans2){
for (int i = 1; i <= num + 1;i++){
printf("%c", s[i]);
}
printf("\n");
continue;
}
}
}
}
return 0;
}
B.Flip and Bits
题目链接
题目大意:
给定一个01序列 a ,每次可以从左往右,从开头确定一个子串,该字串中 1 的个数等于 0 的个数,将这个子串的 0 变为 1,1 变为 0,试判断 a 串是否可以通过多次这样的操作变为 b 串。
解题思路:
我们可以先确定每个子串的右端点,由于不限定次数,所以符合条件的部分可以随意转换,那么对每一段区间两个串不匹配的点进行枚举,只有当不匹配的点为0或全部时,才可以通过转换进行匹配,遍历一遍即可,注意最长的满足条件的子串的右端点不一定为 a 串的最后一个字符,所以要进行特判。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef pair<int, int> PII;
const int N=3e5+10;
int q[N];
char a[N], b[N];
typedef long long ll;
int main()
{
int t;
cin >> t;
while(t--){
int n;
cin >> n;
cin >> a + 1;
cin >> b + 1;
int num0 = 0, num1 = 0;
bool can = 0;
vector<int> ch;
ch.push_back(0);
for (int i = 1; i <= n;i++){
if(a[i]!=b[i]){
can = 1;
}
if(a[i]=='0'){
num0++;
}
if(a[i]=='1')
num1++;
if (num1 == num0)
ch.push_back(i);
}
if(!can){
puts("YES");
continue;
}
else{
bool ans = 0;
if(ch.size()==1){
puts("NO");
continue;
}
for (int i = 1; i < ch.size();i++){
int cnt = 0;
for (int j = ch[i-1]+1; j <= ch[i];j++){
if(a[j]!=b[j]){
cnt++;
}
}
if(cnt>0&&cnt<ch[i]-ch[i-1]){
ans = 1;
break;
}
}
if(ch[ch.size()-1] < n){
for (int j = ch[ch.size() - 1]+1; j <= n;j++){
if(a[j]!=b[j]){
ans = 1;
}
}
}
if(ans){
puts("NO");
}
else
puts("YES");
}
}
return 0;
}
C.Balance the Bits
题目链接
给定一个01序列 s 与a, b两个括号序列,s中第 i 位若为 1 那么a, b 的第 i 位相同,反之则不同,判断能否构成合法的括号序列 a, b如果可以,那么输出这样的序列。
解题思路:
易得a, b两个序列的起始位与末位必须是相同的,所以 s 的初末位必须都为 1 ,那么考虑剩下的部分,对于一个合法的括号序列可得左括号与右括号个数应当是相等的。
由于n规定为偶数,那么对于内部的字符,当存在奇数个 1 时,不管怎么选取都无法满足左右括号数目相同,所以 1 的个数应当为偶数。
下面考虑如何输出合法的序列,对于 s 的2位到n-1位,分别统计0,1的个数,如果0的个数为奇数,那么 a 的这一位输出左括号,反之输出右括号,对1也同理,那么可得此时 a 除端点外的内部一定合法,对b来说,最左边的0与最右边的0分别与两个端点的括号匹配,其余0内部匹配,1也可以内部匹配,所以这样分配是合法的。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef pair<int, int> PII;
const int N=3e5+10;
const int mod = 1e9 + 7;
char s[N];
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--){
memset(s, 0, sizeof s);
int n;
cin >> n;
cin >> s + 1;
int num_0 = 0;
for (int i = 2;i<=n-1;i++){
if(s[i]=='0'){
num_0++;
}
}
if(s[1]!='1'||s[n]!='1'||num_0%2!=0){
cout << "NO" << endl;
continue;
}
cout << "YES" << endl;
vector<char> ans;
ans.push_back('(');
int num0 = 0, num1 = 0;
for (int i = 2; i <= n - 1;i++){
if(s[i]=='0'){
num0++;
if(num0&1){
ans.push_back('(');
}
else
ans.push_back(')');
}
else{
num1++;
if(num1&1){
ans.push_back('(');
}
else
ans.push_back(')');
}
}
ans.push_back(')');
for (int i = 0; i < ans.size();i++){
cout << ans[i];
}
cout << endl;
for (int i = 0; i < ans.size();i++){
if(s[i+1]=='1'){
cout << ans[i];
}
else{
if(ans[i]=='(')
cout << ')';
else
cout << '(';
}
}
cout << endl;
}
return 0;
}
D. 3-coloring
题目链接
题目大意
给定一个n*n的矩阵,有三种颜色可供选择,每次A玩家选定一种颜色,B玩家从剩余的两种颜色里选择一种填在空的格子里,如果有两个相邻的格子的颜色相同,那么B输,反之若填满全部格子且无上述情况B赢,已知B总有办法获胜,下面给定A的每步的选择,输出每一步B选择的颜色与格子。
解题思路
我们先考虑两种颜色的情况,易得若涂成国际象棋盘的形状就是满足条件的,类比到此题,我们可以根据前两个输入来确定棋盘的黑白格对应的颜色。那么优先用对应的颜色来把相应的格子来填满,当出现一种格子已满的时候,那么就填在未满的那种格子里(取不同于已满格子的颜色)。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef pair<int, int> PII;
const int N=3e5+10;
const int mod = 1e9 + 7;
char s[N];
typedef long long ll;
vector<PII> co1, co2;
int n, p1 = 1, p2 = 1;
int cor1, cor2; //记录黑白格代表的颜色
int find_c(int x){
if(x == 1){
return 2;
}
else
return 1;
}
int find_c1(int x, int y){
if(x==y)
return find_c(x);
else{
if(x > y)
swap(x, y);
if(x==1&&y==2)
return 3;
if(x==1&&y==3)
return 2;
if(x==2&&y==3)
return 1;
}
}
void solve(int x){
if(p1==co1.size()){
cout << find_c1(x, cor1) << ' ' << co2[p2].first << ' ' << co2[p2].second << endl;
p2++;
}
else if(p2==co2.size()){
cout << find_c1(x, cor2) << ' ' << co1[p1].first << ' ' << co1[p1].second << endl;
p1++;
}
else{
if(cor1==x){
cout << cor2 << ' ' << co2[p2].first << ' ' << co2[p2].second << endl;
p2++;
}
else{
cout << cor1 << ' ' << co1[p1].first << ' ' << co1[p1].second << endl;
p1++;
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n;i++){
for (int j = 1; j <= n;j++){
if((i+j)%2==0){
co1.push_back({i, j});
}
else{
co2.push_back({i, j});
}
}
}
int a;
cin >> a;
cor1 = find_c(a);
cout << cor1 << " 1 1" << endl;
fflush(stdout);
cin >> a;
cor2 = find_c1(cor1, a);
cout << cor2 << " 1 2" << endl;
fflush(stdout);
int t = n * n - 2;
while(t--){
int a1;
cin >> a1;
solve(a1);
fflush(stdout);
}
return 0;
}