AtCoder Beginner Contest 339
A - TLD
签到
B - Langton's Takahashi
发现步数和网格范围都不大,直接模拟即可
C - Perfect Bus
题目的合法性在于不能为负数,那么初始人数就有了二分性。
二分的找出初始的最小人数,然后跑一边即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
const int N = 4e6 + 10;
int n;
int a[N];
bool check(int mid)
{
int x = mid;
for (int i = 1; i <= n; i++)
{
x = x + a[i];
if (x < 0)
return false;
}
return true;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
int l = 0, r = 1e15;
while (l <= r)
{
int mid = l + r >> 1;
if (check(mid))
r = mid - 1;
else
l = mid + 1;
}
int x = l;
for (int i = 1; i <= n; i++)
{
x = x + a[i];
}
cout << x << endl;
}
signed main()
{
Acode;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
D - Synchronized Players
BFS的练习题,发现60的数据范围支持n^4的暴搜,所以我们就可以有x1,y1,x2,y2的状态来搜索,由于bfs队列内的不减性质,所以率先重合的次数就是答案
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
const int N = 110;
int n;
char mp[N][N];
int mpp[72][72][72][72];
int a[N];
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int vis[N][N];
// woc TLE
struct node
{
int x1, y1;
int x2, y2;
};
// map<array<int, 4>, int> mpp;
int xx1, xx2, yy1, yy2;
int ans = -1;
void bfs1()
{
queue<pair<int, int>> q;
q.push({xx1, yy1});
vis[xx1][yy1] = 1;
while (q.size())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > n)
continue;
if (!vis[dx][dy])
{
vis[dx][dy] = 1;
q.push({dx, dy});
}
}
}
}
void bfs()
{
memset(mpp, 0x3f, sizeof mpp);
mpp[xx1][yy1][xx2][yy2] = 0;
// mpp[{xx1, yy1, xx2, yy2}] = 0;
// 特判-1 试一下算了
queue<node> q;
q.push({xx1, yy1, xx2, yy2});
while (q.size())
{
auto it = q.front();
q.pop();
int x1 = it.x1;
int y1 = it.y1;
int x2 = it.x2;
int y2 = it.y2;
for (int i = 0; i < 4; i++)
{
int dx1 = x1 + dir[i][0];
int dy1 = y1 + dir[i][1];
int dx2 = x2 + dir[i][0];
int dy2 = y2 + dir[i][1];
if (mp[dx1][dy1] == '#' || dx1 <= 0 || dx1 > n || dy1 <= 0 || dy1 > n)
{
dx1 = x1;
dy1 = y1;
}
if (mp[dx2][dy2] == '#' || dx2 <= 0 || dx2 > n || dy2 <= 0 || dy2 > n)
{
dx2 = x2;
dy2 = y2;
}
// mpp[dx1][dy1][dx2][dy2]
// mpp[x1][y1][x2][y2]
if (mpp[dx1][dy1][dx2][dy2] > mpp[x1][y1][x2][y2] + 1)
{
mpp[dx1][dy1][dx2][dy2] = mpp[x1][y1][x2][y2] + 1;
q.push({dx1, dy1, dx2, dy2});
}
if (dx1 == dx2 && dy1 == dy2)
{
ans = mpp[dx1][dy1][dx2][dy2];
return;
}
}
}
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> mp[i][j];
if (mp[i][j] == 'P')
{
if (xx1 == 0)
{
xx1 = i;
yy1 = j;
}
else
{
xx2 = i;
yy2 = j;
}
}
}
}
bfs1();
if (vis[xx2][yy2] == 0)
{
cout << -1 << endl;
return;
}
bfs();
cout << ans << endl;
}
signed main()
{
Acode;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
E - Smooth Subsequence
非常经典的dp,dp[i]的含义为选了第i个数,并且以它结尾的子序列的最长的长度,和LIS非常像。
那么这么想的话,我们是n^2的dp,不能通过。 观察发现就是每次就是从一个范围内,从其中的最大值来转移,所以可以用线段树来优化dp,开的类似与值域线段树,只关系值不关心它的位置。从这个值域内挑一个最大值来转移。
#include <bits/stdc++.h>
using namespace std;
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
#define endl '\n'
const int N = 1e6 + 10;
int a[N];
int dp[N];
// 先写n方的dp转移
struct info
{
int mav;
};
struct node
{
info val;
} seg[N << 2];
info operator+(const info &a, const info &b)
{
info c;
c.mav = max(a.mav, b.mav);
return c;
}
void up(int id)
{
seg[id].val = seg[id << 1].val + seg[id << 1 | 1].val;
}
// void build(int id, int l, int r) // id代表区间节点标号,l,r代表该区间节点的左右端点
// {
// if (l == r)
// {
// seg[id].val = {a[l], 1};
// return;
// }
// int mid = l + r >> 1;
// build(id << 1, l, mid);
// build(id << 1 | 1, mid + 1, r);
// up(id);
// }
void change(int id, int l, int r, int x, int val)
{
if (l == r)
{
seg[id].val = {val};
return;
}
int mid = l + r >> 1;
if (x <= mid)
change(id << 1, l, mid, x, val);
else
change(id << 1 | 1, mid + 1, r, x, val);
up(id);
}
info query(int id, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
return seg[id].val;
int mid = l + r >> 1;
if (qr <= mid) // 同理,查询区间属于左儿子就向左边去找 ,反之是右儿子
return query(id << 1, l, mid, ql, qr);
else if (ql > mid)
return query(id << 1 | 1, mid + 1, r, ql, qr);
else
return query(id << 1, l, mid, ql, qr) + query(id << 1 | 1, mid + 1, r, ql, qr);
}
void solve()
{
int n, d;
cin >> n >> d;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
auto w = query(1, 1, N, max(1LL, a[i] - d), min(N, a[i] + d));
int t = w.mav;
dp[i] = max(dp[i], t + 1);
auto it = query(1, 1, N, a[i], a[i]);
int x = it.mav;
if (x < dp[i])
{
change(1, 1, N, a[i], dp[i]);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
// cerr << dp[i] << " ";
ans = max(ans, dp[i]);
}
cout << ans << endl;
}
signed main()
{
Acode;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
F - Product Equality
赛时没思路,晚上补
G - Smaller Sum
数据结构,晚上补
标签:AtCoder,339,Beginner,int,dy1,dy2,dx2,dx1,mpp From: https://www.cnblogs.com/chenchen336/p/18010277