AtCoder Beginner Contest 339
B - Langton's Takahashi
难度: ⭐⭐
题目大意
给定一个n * m的网格, 并且每一行和每一列都是首尾相连的, 每行的最后一个格子再往右就是这行的第一个格子, 第一个格子向左就是最后一个格子; 列也同理; 默认每个格子初始为白色; 小莫位于(1, 1), 方向朝上;
当小莫位于某个格子时, 如果当前单元格是白色,则将其重新涂成黑色,前进方向顺时针旋转90度,然后沿着他面对的方向向前移动一个单元格。如果是黑色,则将当前单元格重新涂成白色,逆时针旋转90度,然后沿着他所面对的方向向前移动一个单元格。
将上述步骤进行k次, 打印最后格子的颜色分布, '.'表示白色, '#'为黑色;
解题思路
模拟就行, 没啥好说的;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
int g[110][110];
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
signed main(){
int k;
cin >> n >> m >> k;
int a = 1, b = 1, d = -1;
while(k--){
if(g[a][b]){
g[a][b] = 0;
d = (d - 1 + 4) % 4;
a += dx[d], b += dy[d];
}
else{
g[a][b] = 1;
d = (d + 1) % 4;
a += dx[d], b += dy[d];
}
if(a > n) a = 1;
else if(a < 1) a = n;
if(b > m) b = 1;
else if(b < 1) b = m;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(g[i][j]) cout << '#';
else cout << '.';
}
cout << endl;
}
return 0;
}
C - Perfect Bus
难度: ⭐⭐
题目大意
给定一个公交车n个站牌的上下车情况, 这期间车上的人数始终不能小于0, 请问满足条件的最小的初始人数是多少;
解题思路
很简单, 只需要当人数小于0的时候把人数补到0即可;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
int a;
cin >> a;
res += a;
if(res < 0){
res = 0;
}
}
cout << res;
return 0;
}
D - Synchronized Players
难度: ⭐⭐⭐
题目大意
在一个n * n的网格中有两名玩家, 每次我们可以选择上下左右中的一个方向, 两人都朝这个方向前进一格; 如果某人面前是障碍物或者边界则这名玩家不移动; 请问最少进行多少次可以让两名玩家同时位于同一个格子; 无解则输出-1;
解题思路
由于没有什么规律, 所以bfs打暴力即可; 因为数据很小, 所以可以开一个四维数组来去重, 以便判断是否有解;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
int xa, ya, xb, yb;
char g[100][100];
bool st[62][62][62][62];
int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
struct node{
int xa, ya, xb, yb;
int num;
};
bool check(int x, int y){
if(x >= 1 && x <= n && y >= 1 && y <= n && g[x][y] != '#'){
return true;
}
else return false;
}
int bfs(){
queue<node> q;
q.push({xa, ya, xb, yb, 0});
while(q.size()){
auto t = q.front();
q.pop();
if(t.xa == t.xb && t.ya == t.yb){
return t.num;
}
for(int i = 0; i < 4; i++){
int x1 = t.xa + dx[i], y1 =t.ya + dy[i];
int x2 = t.xb + dx[i], y2 =t.yb + dy[i];
if(!check(x1, y1)){
x1 = t.xa, y1 = t.ya;
}
if(!check(x2, y2)){
x2 = t.xb, y2 = t.yb;
}
if(!st[x1][y1][x2][y2]) {
q.push({x1, y1, x2, y2, t.num + 1});
st[x1][y1][x2][y2] = true;
}
}
}
return -1;
}
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cin >> g[i][j];
if(g[i][j] == 'P'){
if(xa) xb = i, yb = j;
else xa = i, ya = j;
}
}
}
cout << bfs();
return 0;
}
E - Smooth Subsequence
难度: ⭐⭐⭐
题目大意
给定一个长度为n的数组A, 求其满足条件的子序列的最大长度是多少;
要求该子序列相邻的数之间差距不能超过m;
解题思路
我一开始想的是用dp, 并且根据题意对于每个数肯定是能接就接; 如果当前进行到了Ai, Ai要接在以(Ai - m, Ai + m)其中一个数结尾的子序列后面, 假设把所有满足条件的子序列后面都接上Ai, 我们发现其实只需要保留其中最长的一个子序列就行, 因为他们都是以Ai, 是等效的; 所以我们可以用线段树来维护以x结尾的子序列的最大长度; 对于Ai就只需要从(Ai - m, Ai + m)中找出最大值即可; 所以其实也用不到dp;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 5e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
int p[N];
struct node{
int l, r;
int maxn;
}tr[4 * N];
void pushup(int u){
tr[u].maxn = max(tr[u << 1].maxn, tr[u << 1 | 1].maxn);
}
void build(int u, int l, int r){
tr[u] = {l, r, 0};
if(l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
void modify(int u, int x, int num){
if(tr[u].l == tr[u]. r && tr[u].l == x){
if(num > tr[u].maxn){
tr[u].maxn = num;
}
}
else{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u << 1, x, num);
else modify(u << 1 | 1, x, num);
pushup(u);
}
}
int query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r){
return tr[u].maxn;
}
else{
int mid = tr[u].l + tr[u].r >> 1;
int res = 0;
if(l <= mid) res = max(res, query(u << 1, l, r));
if(r > mid) res = max(res, query(u << 1 | 1, l, r));
return res;
}
}
signed main(){
cin >> n >> m;
int k = 0;
for(int i = 1; i <= n; i++){
cin >> p[i];
k = max(k ,p[i]);
}
build(1, 1, k);
for(int i = 1; i <= n; i++){
int maxn = query(1, max(0ll, p[i] - m), min(k, p[i] + m));
modify(1, p[i], maxn + 1);
}
cout << query(1, 1, k);
return 0;
}
F - Product Equality
难度: ⭐⭐⭐
题目大意
给定一个长度为n的数组A, 找出满足条件的三元组(i, j, k)的数量: 1 <= i, j, k <= n, 并且 Ai * Aj = Ak;
解题思路
要求很简单, 但是本题的难点在于Ai的范围是101000; 可以用python的大数来做, 如果用c++的话就只能靠哈希来赌了; 为了提高概率这里我们用双哈希; 也就是对于每个Ai, 我们用两个数对其取模, 用这两个数的二元组来代表这个数; 当然不放心的话也可以再多几层哈希;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 5e5 + 10, mod = 998244353, inf = 1000000993;
typedef pair<int, int> PII;
int n, m, res;
int p[2][N];
map<PII, int> mp;
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
string s;
cin >> s;
for(int j = 0; j < s.size(); j++){
p[0][i] = (p[0][i] * 10 + (s[j] - '0')) % mod;
p[1][i] = (p[1][i] * 10 + (s[j] - '0')) % inf;
}
mp[{p[0][i], p[1][i]}]++;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
res += mp[{p[0][i] * p[0][j] % mod, p[1][i] * p[1][j] % inf}];
}
}
cout << res;
return 0;
}