codeforces1301D Time to Run 模拟

网址:https://codeforces.com/contest/1301/problem/D

题意:

给一个$n*m(1 \leq n,m \leq 500)$的格子构成的图,这些格子之间都有两条互为反向的边联通,一条边只能走一次,求从左上角的点开始能不能恰好走完$k$条边?输出时,按照以下格式输出:每行输出一个二元组$a,b$,$a$是次数,$b$是一个只含有$U,D,L,R$的字符串且长度小于$4$,意思是将会从这个点出发按顺序执行$a$次$b$中字符指代的方向,这称为一条指令,在走这$k$条路时最多只能执行$3000$条指令,否则认为不能走完。

题解:

只要$k$小于这些边的数量,就一定能走完,但是因为有指令数量限制,所以就需要尽可能规律地走,就可以将这些重复走法合并成一条指令。然后怎么走会规律呢?我们考虑一种尽可能多直线的走法。先向右横着走$m-1$格,然后向左$m-1$格,然后向下一格,然后可以这样子走$n-1$个循环。然后向右$m-1$格,同样的道理走纵向。总共只需要走$(3*m-3)*(n-1)+(3*n-3)+2$条边。

然后我们为了降低编程难度,先编程算出所有的规律的路径保存起来,然后就找长度是刚好是$k$的就指令就可以了,具体看代码。

AC代码:

#include 
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
vector >v, ans;
#define pb push_back
#define mp make_pair
#define len(x) (x.first*x.second.size())
void init(int n, int m)
{
	v.clear();
	ans.clear();
	for (int i = 1; i <= n; ++i)
	{
		if (i < n)
		{
			v.push_back(mp(m - 1, "R"));
			v.push_back(mp(m - 1, "L"));
			v.push_back(mp(1, "D"));
		}
		else
			v.push_back(mp(m - 1, "R"));
	}
	for (int i = 1; i <= m; ++i)
	{
		if (i < m)
		{
			v.push_back(mp(n - 1, "U"));
			v.push_back(mp(n - 1, "D"));
			v.push_back(mp(1, "L"));
		}
		else
			v.push_back(mp(n - 1, "U"));
	}
}
int solve()
{
	int n, m, k;
	scanf("%d%d%d", &n, &m, &k);
	if (k > 4 * n * m - 2 * m - 2 * n)
		return printf("NO\n"), 0;
	init(n, m);
	for (auto i : v)
	{
		if (k > len(i))
		{
			if (i.first)
				ans.push_back(i), k -= len(i);
		}
		else
		{
			int di = k / i.second.size();
			int le = k % i.second.size();
			if (di)
				ans.push_back(mp(di, i.second));
			for (int j = 0; j < le; ++j)
				ans.push_back(mp(1, string(1, i.second[j])));
			break;
		}
	}
	printf("YES\n%d\n", ans.size());
	for (auto i : ans)
		printf("%d %s\n", i.first, i.second.c_str());
	return 0;
}
int main()
{
	int t = 1;
	//scanf("%d", &t);
	while (t--)
		solve();
	return 0;
}

 

你可能感兴趣的:(codeforces1301D Time to Run 模拟)