Codeforces Global Round 9 A~D题解

传送门

  • A.Sign Flipping
  • B.Neighbor Grid
  • C.Element Extermination
  • D.Replace by MEX

A.Sign Flipping

       题意:给一个包含 n n n个整数的数组,可以随意改变他们的正负号使得至少有 n − 1 2 \frac{n-1}{2} 2n1个相邻数字的差 ≥ 0 \ge0 0,且至少有 n − 1 2 \frac{n-1}{2} 2n1个相邻数字的差 ≤ 0 \leq0 0
       对于任意的三个数字 a a a, − b -b b, c c c,其中 a a a, b b b, c c c > 0 0 0,一定符合以上我们所说的要求。我们再延申至任意长度的数组。

int n, k;
int a[105];
void solve()
{
	cin >> n;
	bool f = 1;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		a[i] = abs(a[i]);
	}
	for (int i = 1; i <= n; i++)
	{
		if (f)cout << a[i] << " ";
		else cout << -a[i] << " ";
		f ^= 1;
	}
	cout << endl;
}

B.Neighbor Grid

       题意:给一个 n × m n×m n×m的矩阵,由非负整数填充。我们定义一个good矩阵:对于每一个格子,他的数字一定等于他的所有相邻格子当中格子的数字大于 0 0 0的数量。我们可以给任意一个格子的数字+1,并且可以执行任意次。问最初给的矩阵能否变成good矩阵。
       首先看到这是B题,我们不可能会用DFS去做。对于一个格子,如果他处在矩阵边界,他的邻居数量就会少于4,那么如果他的数字小于邻居数量,输出NO就完了。剩下的,我们把每个格子都改成他的邻居数量。

int n, k, m;
int a[305][305];
bool check(int i, int j)
{
	return i >= 1 && i <= n && j >= 1 && j <= m;
}//判断这个点存不存在这个矩阵中,就是判断有没有这个邻居
void solve(int T)
{
	cin >> n >> m;
	bool f = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			cin >> a[i][j];
			int num = 0;
			if (a[i][j] > 0)
			{//判断4个方向的邻居
				if (check(i + 1, j))num++;
				if (check(i - 1, j))num++;
				if (check(i, j + 1))num++;
				if (check(i, j - 1))num++;
				if (num < a[i][j])f = 1;
			}
		}
	if (f)cout << "NO\n";
	else
	{
		cout << "YES\n";
		for (int i = 1; i <= n; i++, cout << endl)
			for (int j = 1; j <= m; j++)
			{
				int num = 0;
				if (check(i + 1, j))num++;
				if (check(i - 1, j))num++;
				if (check(i, j + 1))num++;
				if (check(i, j - 1))num++;
				cout << num << " ";
			}
	}
}

C.Element Extermination

       题意:给一个数组,他是 [ 1 , n ] [1,n] [1,n]的一个全排列,每次我们可以选择相邻的两个数字 a i a_i ai, a a ai+1,其中 a i a_i ai< a a ai+1,然后删去其中一个,问最后能否只剩下一个数字。
       我们知道,当最后的两个数字 x x x y y y符合 x x x< y y y,才能成功。我们从后往前看,在能成功的前提下(即左边的数小于右边的数),我们在 x x x y y y的中间插入任何一个数字,都是可以化简成“只有两个数字且右边的数大于左边的数“这种情况(在 x x x y y y两边插入的话就不一定符合能成功的前提)。我们再以此延申至任意长度的数组,只要判断 a 1 a_1 a1是否< a n a_n an就ok了。

int n, k, m;
int a[300005];
void solve(int T)
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	if (a[1] > a[n])cout << "NO\n";
	else cout << "YES\n";
}

D.Replace by MEX

       题意:我们定义 m e x mex mex为当前数组中没出现过的最小非负整数,他们都在 0 0 0 n n n之间。给一个包含n个非负整数的数组。我们每次操作可以选择一个数字,并把它替换成当前的 m e x mex mex,问使得数组呈非递减状态的操作过程。n的范围是1000,可以非常暴力得A掉。每次操作,我们找出当前的 m e x mex mex,并且把 a a a m e x mex mex的位置改成 m e x mex mex,重复该操作直到数组非递减即可。但是要注意一个特殊情况,如果当前的 m e x mex mex n n n,超出了数组长度,我们就要找出一个错误的位置(具体怎么才算错误,见代码)改成 m e x mex mex,再进行下面的操作。详细操作见代码。

#define pb push_back
#define vint vector
int n, k, m;
int a[1005], b[1005];
void solve(int T)
{
	vint ans;
	cin >> n;
	int mex = 0;
	for (int i = 0; i < n; i++)cin >> a[i];
	while (1)
	{   //这里判断数组是否是非递减的
		bool f = 0;
		for (int i = 0; i < n - 1; i++)
			if (a[i + 1] < a[i])f = 1;
		if (!f)break;
 		//这里找出mex,很笨的方法
		for (int i = 0; i < n; i++)b[i] = a[i];
		sort(b, b + n);
		mex = 0;
		for (int i = 0; i < n; i++)
			if (b[i] == mex)mex++;
 		//如果mex超出数组长度了
		if (mex == n)
		{	//找出改成mex的位置-i
			int i;
			for (i = 0; i < n; i++)
				if (a[i] != i)break;
			ans.pb(i);
			a[i] = mex;
			continue;
		}
		ans.pb(mex);
		a[mex] = mex;
	}
	cout << ans.size() << endl;
	for (int x : ans)cout << x + 1 << " ";//这里我们数组从0开始,所以输出要+1
	cout << endl;
}

只可惜在赛场写的D没有通过fst,本来可以加100多分,最后只加了50分,心疼。比完了去看t神的D题代码,写的很清楚,这里贴一下地址。他的思路和我不一样的点在于,如果当前mex为n,直接把数组最后一个数改成mex,然后数组长度n- -,即无视掉最后一个数字,不加入后面的操作。

你可能感兴趣的:(总结)