前面两道阅读理解直接跳过。
C - Loong Tracking
大意
二维网格,贪吃蛇,移动,进行q次操作,分两种:
- 指定贪吃蛇下一步移动的方向
- 指定i,输出贪吃蛇的第 i个部位的坐标。
思路
每移动一次,只有头部到了新的坐标,其他部分的坐标都变成前一个。
如果我们把每个部分的坐标按顺序放在一个队列里,队尾是头部坐标,队头是尾部坐标,每次移动相当于一次出队和一次入队。
但是std::queue不支持下标访问,所以用std::vector(出队可以不操作)。
问第i个部位坐标就从队尾倒着数即可。
代码
#include<iostream>
#include<vector>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
vector<pll> a;
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
ll n, q;
cin >> n >> q;
for(int i = 0; i < n; i++) a.push_back(make_pair(n - i, 0));
while(q--){
ll t;
cin >> t;
if(t == 1){
string dir;
cin >> dir;
pll last = a.back();
if(dir == "R") last.first++;
if(dir == "L") last.first--;
if(dir == "D") last.second--;
if(dir == "U") last.second++;
a.push_back(last);
}else{
ll p;
cin >> p;
cout << a[a.size() - p].first << " " << a[a.size() - p].second << endl;
}
}
return 0;
}
D - Loong and Takahashi
大意
给定一个的二维网格,
为奇数,给每个格子一个数字
,要求每个数字仅使用一次,且相邻数字的格子相邻,且正中间的格子不能是数字,而是
T
。
给出一种构造方法。
思路
螺旋构造即可。
每次一个螺旋回字构造就填充最外围的一圈,起点依次为 ,最后恰好到正中间,因此能恰好填满。
代码
#include <iostream>
#include <vector>
using namespace std;
void fillin(int e, vector<int> position, int start, vector<vector<int>> &grid){
for(int i = 0; i < e; i++) grid[position[0]][position[1]++] = start++;
for(int i = 0; i < e; i++) grid[position[0]++][position[1]] = start++;
for(int i = 0; i < e; i++) grid[position[0]][position[1]--] = start++;
for(int i = 0; i < e; i++) grid[position[0]--][position[1]] = start++;
}
int main(){
ios::sync_with_stdio(0);
int N;
cin >> N;
vector<vector<int>> grid(N, vector<int>(N));
vector<int> p = {0, 0};
int count = 1;
for(int i = N - 1; i > 0; i -= 2){
fillin(i, p, count, grid);
p[0]++;
p[1]++;
count += i * 4;
}
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
if(i == (N + 1) / 2 - 1 && j == (N + 1) / 2 - 1) cout << "T ";
else cout << grid[i][j] << " ";
}
cout << endl;
}
return 0;
}
E - Non-Decreasing Colorful Path
大意
给定一个个点
条边的无向图,图上每个点都有其颜色。求所有经过点权单调不降的
到
的路径中,出现的不同颜色的个数最多是多少。
思路
对于的情况下,该边一定是无效的,所以我们只往图中添加
的边,注意这是一个无向图,所以需要判断正反两次。
然后普通的dijkstra肯定是不行的,需要更改下面这些逻辑:
- 对于优先队列:如果两者点权相同,那么优先选择从1到该点路径上不同颜色更多的,否则选择点权更小的。注意优先队列的优先级与cmp是反的。
- 对于dijkstra跑图过程:如果遍历到的点的点权大于现在这个点,答案数会加一。
代码
#include<iostream>
#include<queue>
using namespace std;
const int N = 2e5 + 9;
int n, m, a[N], dis[N];
vector<int> G[N];
struct Node{
int id, cnt;
Node(int x, int y): id(x), cnt(y) {};
bool operator < (const Node q) const{
return (a[id] == a[q.id]? cnt < q.cnt: a[id] > a[q.id]);
}
};
void dijkstra(int st){
priority_queue<Node> q;
dis[st] = 1;
q.push(Node(st, 1));
while(q.size()){
auto x = q.top();
q.pop();
for(int v: G[x.id]){
if(dis[v] < dis[x.id] + (a[x.id] < a[v])){
dis[v] = dis[x.id] + (a[x.id] < a[v]);
q.push(Node(v, dis[v]));
}
}
}
}
void add(int u, int v){
if(a[u] <= a[v]) G[u].push_back(v);
if(a[v] <= a[u]) G[v].push_back(u);
}
int main(){
ios::sync_with_stdio(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1, u, v; i <= m; i++){
cin >> u >> v;
add(u, v);
}
dijkstra(1);
cout << dis[n] << endl;
return 0;
}