【解题报告】CF DIV2 #ROUND 712 A~D

【解题报告】CF DIV2 #ROUND 707 A~D

比赛链接
字符串专场hh
5059名,失误挺多的,不过还好连跪三把之后没有继续掉分,回升了一点

A.Déjà Vu

思路
这次A题没有一发瞬秒而且严重拖慢了进度,原本憨憨交了一发TLE。
思路还是很简单的,如果全是a那就输出NO,反之可以插入得到非回文串,接下来让我们瞅瞅原本TLE的代码
TLE代码

// Problem: A.  Déjà Vu
// Contest: Codeforces - Codeforces Round #712 (Div. 2)
// URL: https://codeforces.com/contest/1504/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;

/*DATA & KEY
t 1 1e4
s len 3*1e5
*/
int T;

void solve(int T)
{
	//NEW DATA CLEAN
	map<char,int>mp;
	mp.clear();
	//NOTE!!!
	string s;
	cin>>s;
	int len=s.size();
	for(int i=0;s[i];i++)mp[s[i]]++;
	if(mp.size()==1&&mp['a']>0)puts("NO");
	else
	{
		string in="a";
		string A=in+s;
		string tmp_A=A;
		reverse(tmp_A.begin(),tmp_A.end());
		if(tmp_A!=A)
		{
			puts("YES");
			cout<<A<<endl;
		}
		else
		{
			for(int i=0;s[i];i++)
			{
				string a=s.substr(0,i)+in+s.substr(i);
				string tmp=a;
				reverse(tmp.begin(),tmp.end());
				if(a!=tmp)
				{
					puts("YES");
					cout<<a<<endl;
					break;
				}
			}
		}
	}
}

int main()
{
	scanf("%d",&T);
	while(T--)solve(T);
	return 0;
}

显然的,我们对STL的reverse函数复杂度太不熟悉了,reverse操作时间复杂度为 O ( N ) O(N) O(N),我以为是 O ( 1 ) O(1) O(1)然后瞬间TLE啊啊啊。
如果构造类似这种右边a比左边多1个的,就要循环好几遍

aaaaaabaaaaaaa

然后改进了一下思路,其实要插成非回文串只要看看在开头插入和在末尾插入即可,哪个ok输出哪个

AC代码

// Problem: A.  Déjà Vu
// Contest: Codeforces - Codeforces Round #712 (Div. 2)
// URL: https://codeforces.com/contest/1504/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;

/*DATA & KEY
t 1 1e4
s len 3*1e5
*/
int T;

void solve(int T)
{
	//NEW DATA CLEAN
	//NOTE!!!
	bool flag=1;
	string s;
	cin>>s;
	int len=s.size();
	for(int i=0;s[i]&&flag;i++)
	{
		if(s[i]!='a')flag=0;
	}
	if(flag)puts("NO");
	else
	{
		puts("YES");
	 	string A="a"+s;
	 	string B=s+"a";
	 	string a,b;
	 	a=A,b=B;
	 	reverse(a.begin(),a.end());
	 	reverse(b.begin(),b.end());
	 	if(a!=A)cout<<A<<endl;
	 	else cout<<B<<endl;	
	}
}

int main()
{
	scanf("%d",&T);
	while(T--)solve(T);
	return 0;
}

B. Flip the Bits

思路
花了20分钟一发过了,爽唉。
先遍历一遍,把所有允许的前缀操作记录一波,我用了map,其实bool数组就ok了数据范围挺小的
题目要求字符串a通过前缀处理变成字符串b,前缀处理的话要考虑后面的覆盖问题。所以我们反过来由字符串b变成字符串a,这样的话,保证最新一次操作是不会被之前操作所影响的。
代码

// Problem: B. Flip the Bits
// Contest: Codeforces - Codeforces Round #712 (Div. 2)
// URL: https://codeforces.com/contest/1504/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;

/*DATA & KEY
T 1 1E4
sum n 1 3e5
*/
int T;
void solve(int T)
{
	//NEW DATA CLEAN
	//NOTE!!!
	int n;cin>>n;
	string a,b;cin>>a>>b;
	map<int,int>mp;
	int c1=0,c0=0;
	for(int i=0;i<n;i++)
	{
		if(a[i]=='0')c0++;
		else c1++;
		if(c0==c1)mp[i]++;
	}
	bool flag=1,ans=1;
	for(int i=n-1;i>=0;i--)
	{
		bool aa=a[i]-'0';
		bool bb=b[i]-'0';
		 bb=flag?bb:(!bb);//标记反转
		if(aa!=bb)//从一但不同就看能不能翻转
		{
			if(mp.find(i)!=mp.end())flag=!flag;
			else {ans=0;break;}
		}
	}
	if(ans)puts("YES");
	else puts("NO");
}

int main()
{
	scanf("%d",&T);
	while(T--)solve(T);
	return 0;
}

C. Balance the Bits

思路
构造题
平衡括号串就是合法括号配对嘛,然后首先想到了利用栈来判断括号配对是否合法,然后瞎搞了一波直接白给,后面想了个贪心构造的结果写了一堆后忘记是要输出构造结果的,还有五分钟直接放弃
参考了这个大佬的博客
《很 了 解 平 衡 括 号 串》
在这里插入图片描述
新知识get!
然后可以确定的是开头和结尾一定是(和)组成的,因此字符串首尾必是1
假设原来全都是1,所以如果有一个变为0,那么肯定会产生一个不匹配的括号,因此需要再来一个0来抵消这次不匹配,所以0的数量一定是偶数

那么如何构造呢?比赛的时候构造有问题,后来参看了这个大佬的博客
根据特性2:任意前缀的)的数目不能大于(
所以我们构造的时候要保证两个串在当前位置(数量比)多,对于最后一个位置我们已经确定了一定是),所以不用特别处理

()一样大,前缀(一直比)多,用0来抵消0 基于这三点我们进行如下构造
前一半1为(,后一半为)
奇数次0,a加(,b加)
偶数次0,a加),b加(

代码

// Problem: C. Balance the Bits
// Contest: Codeforces - Codeforces Round #712 (Div. 2)
// URL: https://codeforces.com/contest/1504/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;

/*DATA & KEY
t 1 1e4
sum n 2 2e5
n even
*/
int T;

void solve(int T)
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	int n;cin>>n;
	string s;cin>>s;
	int cnt=0;
	for(int i=0;s[i];i++)
		if(s[i]=='0')cnt++;
	int mid=(n-cnt)/2;//标记前一半1的数量
	if((cnt&1)||s[0]=='0'||s[n-1]=='0')puts("NO");
	else
	{
		string a,b;
		int ca=0,cb=0;
		bool flag=1;
		puts("YES");
		for(int i=0;i<n;i++)
		{
			if(s[i]=='1')
			{
				ca++;
				if(ca<=mid)a+='(',b+='(';
				else a+=')',b+=')';
			}
			else
			{
				if(flag)a+='(',b+=')';
				else a+=')',b+='(';
				flag=!flag;
			}
		}
		cout<<a<<endl<<b<<endl;
	}
}

int main()
{
	scanf("%d",&T);
	while(T--)solve(T);
	return 0;
}

D. 3-Coloring

思路
交互题,蛮新奇的以前没碰到过。参考了繁凡巨佬的博客才知道要干嘛。
染色问题,总共可以染三种颜色,相邻格子颜色不能相同。每次会告诉你一种颜色不能染的,问你如何把nxn的棋盘染满。
不相邻染色可以想到黑白二分图染色,不过这个有三个颜色咋整嘞,可以转成两次不相邻二染色。
先按照繁凡巨佬说的预处理棋盘,可以发现黑白可以分为i+j为偶数和奇数的两种。
第一次二染色:颜色1全填黑,另外两种全填白
第二次二染色:黑的或者白的一种填完了,那就随便填,因为相邻的已经被黑或者白块全部分隔开了
在这里插入图片描述

代码
借(完)鉴(全)了(照)一(搬)波

// Problem: D. 3-Coloring
// Contest: Codeforces - Codeforces Round #712 (Div. 2)
// URL: https://codeforces.com/contest/1504/problem/D
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// FishingRod
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;

/*DATA & KEY

*/
int T;
int n,m;
const int N=3;
vector<PII>pos[N];
void solve()
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++)//棋盘预处理
		for(int j=1;j<=n;j++)
			pos[((i+j)&1)+1].push_back(make_pair(i,j));//写得好精简啊
	
	for(int i=1;i<=n*n;i++)
	{
		int ban,col;//ban表示禁掉的,col表示选的颜色
		PII position;
		scanf("%d",&ban);
		if(ban==1)
		{
			if(pos[2].size())//如果还没被填满
			{
				col=2;
				position=pos[2].back();
				pos[2].pop_back();
			}
			else
			{
				col=3;
				position=pos[1].back();
				pos[1].pop_back();
			}
		}
		else if(ban==2)
		{
			if(pos[1].size())
			{
				col=1;
				position=pos[1].back();
				pos[1].pop_back();
			}
			else
			{
				col=3;
				position=pos[2].back();
				pos[2].pop_back();
			}
		}
		if(ban==3)
		{
			if(pos[1].size())
			{
				col=1;
				position=pos[1].back();
				pos[1].pop_back();
			}
			else if(pos[2].size())
			{
				col=2;
				position=pos[2].back();
				pos[2].pop_back();
			}
		}
		printf("%d %d %d\n",col,position.first,position.second);
		fflush(stdout);//交互题一定要加这玩意,而且别用endl因为自己换成\n了没刷新
	}
}

int main()
{
//	scanf("%d",&T);
//	while(T--)solve(T);
	solve();
	return 0;
}

反思

A:

STL reverse:
时间复杂度为 O ( N ) O(N) O(N)

错误的写法
tmp=reverse(tmp_A.begin(),tmp_A.end());
reverse(tmp);
正确的写法
reverse(tmp_A.begin(),tmp_A.end());

B:

前缀操作涉及覆盖的可以逆向思考,反向操作,从后向前遍历,保证本次操作后半部分的效果不会被新操作的覆盖。
在这里插入图片描述

C:

平衡括号串(合法括号串)特性与联想:

  1. (和)各占一半
  2. 开头和结尾分别为(和)
  3. 对于任意前缀(一定比)数量多
  4. 联想到用栈来判断是否合法
    其中1,3为平衡括号串的充要条件

对于这题里的匹配的联想:如果出现某个操作使得原本匹配的变成不匹配了,就思考如何抵消本次操作造成的影响来变成合法的。可能是再进行一次这种操作,也可能是选择别的操作。另外很多时候可以把两个不匹配的配对变成匹配的,原本匹配的就和原本匹配的配对

D:

不相邻染色联想到二分图二染色问题,多种颜色可以分为多次而染色。先预处理出黑白棋盘,加入黑白染色队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值