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 <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; typedef long long ll; vector<pair<int, string> >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; }