2024暑期集训补题(构造)

牛客多校2 A题

在这里插入图片描述
题意:
给定两种图形 A , B A,B A,B,要求构造一个 n ⋅ m n \cdot m nm的由 A , B A,B A,B两种图案构成的矩形,同时满足矩形中的曲线数量恰好为 k k k个,并限制了某个 ( x , y ) (x,y) (x,y)位置上的图形必须为 A A A或者 B B B

题解:
考虑从左上角开始构造,左上角第一个图案的贡献必然是 2 2 2,仅向右继续拼接时,无论是 A A A还是 B B B,每添加一个新的图案,贡献也必然是 1 1 1,向下同理,当第一行和第一列构造完后,其贡献值必然为 n + m n + m n+m,继续向右下角构造,我们可以发现每添加一个新的图案,其贡献要么为 1 1 1,要么为 0 0 0,所以显然,最终结果的最小值一定是 n + m n + m n+m,如果我们想让右下角的贡献为 1 1 1,我们可以构造出类似于单位圆一样的图形,每产生一个单位圆,总贡献值会 + 1 +1 +1,当且仅当 2 ∗ 2 2*2 22的图案为 A B , B A AB,BA AB,BA时产生一个单位圆,那么显然我们只需要先去构造出最多的单位圆,判断答案是否小于当前图案且大于等于 n + m n + m n+m,如果符合要求,我们从左上角开始一行一行遍历,将 B B B变成 A A A或者将 A A A变成 B B B,这样可以实现一个一个消除单位圆,当剩余单位圆的数量满足条件时,输出答案即可。

还有一点需要注意的是题目限制了某个位置的固定图案,因此我们可以通过奇偶性去判断最多的单位圆图案的左上角应该是 A A A还是 B B B,然后按照原来的规则一步一步去消除单位圆即可。

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define debug(p) for (auto i : p)cerr << i << " "; cerr << endl;
#define debugs(p) for (auto i : p)cerr << i.first << " " << i.second << endl;
typedef pair<int, int> pll;
string yes = "Yes";
string no = "No";
int last = 0;
int area(int i, int j, int op)
{
	int a = ((i - 1) * (j - 1) + 1) / 2;
	int b = (i - 1) * (j - 1) / 2;
	if(op == 1)return a;
	else return b;
}
char ans[817][817];
void solve()
{
	int n, m, k;
	cin >> n >> m >> k;
	int x, y;
	string temp;
	cin >> x >> y >> temp;
	if(k < n + m)
	{
		cout << no << endl;
		return;
	}
	if((x + y) % 2 == 0 && temp == "A" || (x + y) % 2 && temp == "B")last = 1;
	else last = 2;
	k -= (n + m);
	if(last == 1)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if((i + j) % 2 == 0)ans[i][j] = 'A';
				else ans[i][j] = 'B';
			}
		}
		int tot = area(n, m, 1);
		if(k > tot)
		{
			cout << no << endl;
			return;
		}
		for (int j = 1; j <= m; j++)
		{
			if(tot == k)break;
			for (int i = 1; i <= n; i++)
			{
				if(temp == "B")
				{
					if(i + 1 <= n && j + 1 <= m && ans[i][j] == 'A' && ans[i + 1][j + 1] == 'A' && ans[i + 1][j] == 'B' && ans[i][j + 1] == 'B')
					{
						tot--;
						ans[i][j] = 'B';
					}
					ans[i][j] = 'B';
				}
				else
				{
					if(i - 1 > 0 && j + 1 <= m && ans[i][j] == 'B' && ans[i - 1][j + 1] == 'B' && ans[i - 1][j] == 'A' && ans[i][j + 1] == 'A')
					{
						tot--;
						ans[i][j] = 'A';
					}
					ans[i][j] = 'A';
				}
				if(tot == k)break;
			}
			if(tot == k)break;
		}
	}
	else
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if((i + j) % 2 == 0)ans[i][j] = 'B';
				else ans[i][j] = 'A';
			}
		}
		int tot = area(n, m, 2);
		if(k > tot)
		{
			cout << no << endl;
			return;
		}
		for (int j = 1; j <= m; j++)
		{
			if(tot == k)break;
			for (int i = 1; i <= n; i++)
			{
				if(temp == "B")
				{
					if(i + 1 <= n && j + 1 <= m && ans[i][j] == 'A' && ans[i + 1][j + 1] == 'A' && ans[i + 1][j] == 'B' && ans[i][j + 1] == 'B')
					{
						tot--;
						ans[i][j] = 'B';
					}
					ans[i][j] = 'B';
				}
				else
				{
					if(i - 1 > 0 && j + 1 <= m && ans[i][j] == 'B' && ans[i - 1][j + 1] == 'B' && ans[i - 1][j] == 'A' && ans[i][j + 1] == 'A')
					{
						tot--;
						ans[i][j] = 'A';
					}
					ans[i][j] = 'A';
				}
				if(tot == k)break;
			}
			if(tot == k)break;
		}
	}

	cout << yes << endl;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cout << ans[i][j];
		}
		cout << endl;
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}
}
  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值