Codeforces Round #712 (Div. 2) A~E 题解

本场链接:Codeforces Round #712 (Div. 2)

A. Déjà Vu

签到题,尝试一下插入首位元素或者插入第一个不是a的位置.两者都不行必然是NO.

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

bool check(const string& s)
{
	string r = s;
	reverse(r.begin(),r.end());
	return r != s;
}

int main() 
{
	Angel_Dust;
	int T;cin >> T;
	while(T--)
	{
		string s;cin >> s;
		string ans = "a" + s;
		if(check(ans))
		{
			cout << "YES
";
			cout << ans << "
";
			continue;
		}
		
		int ins = 0;
		ans = "";
		for(auto& v : s)
		{
			ans += v;
			if(v == 'a' || ins)	continue;
			ans += 'a';
			ins = 1;
		}
		if(!ins)
		{
			cout << "NO
";
			continue;
		}
		if(check(ans))
		{
			cout << "YES
";
			cout << ans << "
";
			continue;
		}
		cout << "NO
";
	}
	return 0;
}

B. Flip the Bits

考虑倒着在B串上进行修改.维护当前的前缀有多少个0/1,如果当前这一位与A不同则必然需要翻转当前枚举的前缀,因为此后就不能对这一位产生任何影响了.若中途出错了则无解,否则成功.

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)


int main() 
{
	Angel_Dust;
	int T;cin >> T;
	while(T--)
	{
		int n;cin >> n;
		string sa,sb;cin >> sa >> sb;
		int flag = 0,ok = 1;
		int s0 = 0,s1 = 0;
		for(auto& v : sb)	if(v == '0')	++s0;else ++s1;
		forr(i,0,n - 1)
		{
			int v = sb[i] - '0';
			if(flag)	v ^= 1;
			// cout << i << " " << v << endl;
			// cout << s0 << " " << s1 << endl;
			if(v != sa[i] - '0')
			{
				if(s1 != s0)
				{
					// cout << i << endl;
					// cout << s1 << " " << s0 << endl;
					ok = 0;
					break;
				}
				v ^= 1;
				// cout << "changed " << i << endl;
				flag ^= 1;
			}
			if(v)	--s1;else --s0;
		}
		if(ok)	cout << "YES
";
		else cout << "NO
";
	}
	return 0;
}

C. Balance the Bits

由于(s[i]=0)的位置的存在非常的吊比,如果他们不存在,那么剩下的(s[i]=1)的位置事实上只需要前一半填左后一半相反就可以了.那么怎么样让(s[i]=0)的位置填入的括号对于整个序列来说是独立的部分呢?奇偶性填充即可.

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)


int main() 
{
	Angel_Dust;
	int T;cin >> T;
	while(T--)
	{
		int n;cin >> n;
		string s;cin >> s;
		
		string act,ans;
		int c0 = 0,c1 = 0;
		for(auto& v : s)
		{
			if(v == '0')	++c0;
			else ++c1;
		}
		if(c0 % 2 || c1 % 2)
		{
			cout << "NO
";
			continue;
		}
		
		int _0 = 0,_1 = 0;
		for(auto& v : s)
		{
			if(v == '0')
			{
				++_0;
				if(_0 % 2 == 1)	act += '(';
				else	act += ')';
			}
			else
			{
				++_1;
				if(_1 <= c1 / 2)	act += '(';
				else	act += ')';
			}
		}
		forn(i,0,n - 1)
		{
			if(s[i] == '1')	ans += act[i];
			else
			{
				if(act[i] == ')')	ans += '(';
				else ans += ')';
			}
		}
		int sum = 0,ok = 1;
		forn(i,0,n - 1)
		{
			if(ans[i] == '(')	++sum;
			else --sum;
			if(sum < 0)	ok = 0;
		}
		if(sum != 0)	ok = 0;
		if(ok)	cout << "YES
" << act << "
" << ans << "
";
		else cout << "NO
";
	}
	return 0;
}

D. 3-Coloring

直觉:对棋盘三染色,但是不难发现如果对手全给相同的输入,必然是不能完全填满的.考虑二染色:二染色只能直接地处理颜色有两种的情况,那不妨先把这种情况写进去:黑色位置全部填1,白色位置全部填2.剩下的第三种颜色在对手取(3)的时候显然取不到,那么只有另外两种情况可能需要填入这种颜色,贪心构造:只有当1或者2已经填满的时候,才往棋盘上放置3.

考虑正确性:极端情况是只填1/2颜色,显然二染色是直接满足条件的.其他情况,如果需要填入3必然是某种颜色已经填满了而另外一种还没有,在这样的已经完全填满了某种颜色的格图上所有的剩下的格子也必然不相连,所以不会出现相邻.

如果硬做三染色应该是没什么出路的.

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 105;
int ans[N][N];

int main() 
{
	Angel_Dust;
	int n;cin >> n;
	forn(i,1,n)	forn(j,1,n)	ans[i][j] = 0;
	forn(i,1,n)	forn(j,1,n)
	{
		int bx = 0,by = 0,wx = 0,wy = 0;
		forn(x,1,n)	forn(y,1,n)
		{
			if((x + y) % 2 == 0 && !ans[x][y])	bx = x,by = y;
			if((x + y) % 2 == 1 && !ans[x][y])	wx = x,wy = y;
		}
		int a;cin >> a;
		if(a == 1)
		{
			if(bx)	ans[bx][by] = 2,cout << 2 << " " << bx << " " << by << endl;
			else	ans[wx][wy] = 3,cout << 3 << " " << wx << " " << wy << endl;
		}
		else if(a == 2)
		{
			if(wx)	ans[wx][wy] = 1,cout << 1 << " " << wx << " " << wy << endl;
			else	ans[bx][by] = 3,cout << 3 << " " << bx << " " << by << endl;
		}
		else
		{
			if(bx)	ans[bx][by] = 2,cout << 2 << " " << bx << " " << by << endl;
			else	ans[wx][wy] = 1,cout << 1 << " " << wx << " " << wy << endl;
		}
	}

	return 0;
}

E. Travelling Salesman Problem

思维题,挺申必的.

结论:起点事实上是无用条件,因为整个路径是一个环路,选择任何一个环上的点作为起点不会有影响.

转换:(max(c_i,a_j-a_i) = max(0,a_j - a_i - c_i) + c_i).因为每个点都必然会离开自己这个点一次,所以(c_i)部分是固定的常数累加即可,考虑最小化(max(0,a_j-a_i - c_i))的和.

不难想到如果(a_j leq a_i)那么路径的权必然是(0),即没有贡献.根据结论,不妨将所有点按(a_i)排序,所有位置靠后的点往前走的时候是没有代价的,所以对于每个点(iin [2,n])来说,他在路径中可以是任何一个点(j<i)走过来的.那么只需要求每个点从前面的点转移过来的代价和就可以了,反正往前走是没有代价的.答案等于统计(sumlimits_{i=2}^n max(0,a_i - (a_j + c_j))).考虑维护(j<i)的最大的(a_j+c_j)即可.

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define forr(i,x,n)	for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
typedef pair<int,int> pii;
#define x first
#define y second

const int N = 1e5+7;
pii a[N];

int main() 
{
	int n;scanf("%d",&n);
	
	forn(i,1,n)	scanf("%d%d",&a[i].x,&a[i].y);
	sort(a + 1,a + n + 1);
	
	priority_queue<int> pq;
	pq.push(a[1].x + a[1].y);
	
	ll res = 0;
	forn(i,2,n)
	{
		res += max(0,a[i].x - pq.top());
		pq.push(a[i].x + a[i].y);
	}
	
	forn(i,1,n)	res += a[i].y;
	
	printf("%lld
",res);
	return 0;
}
原文地址:https://www.cnblogs.com/HotPants/p/14616059.html