AtCoder Beginner Contest 257 A - F
vp 了一场之前的 ABC,不知道是水平下降还是真的难,就很多要想很久,寄了
A - A to Z String 2
向下取整考虑一下是在哪个组就好
#include <iostream>
using namespace std;
int main()
{
int n, x;
cin >> n >> x;
x--;
x /= n;
cout << (char)('A' + x) << endl;
return 0;
}
B - 1D Pawn
模拟
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 10;
int num[maxn], vis[maxn];
int main()
{
int n, k, q;
cin >> n >> k >> q;
for(int i=1; i<=k; i++)
{
cin >> num[i];
vis[num[i]] = i;
}
while(q--)
{
int x;
cin >> x;
vis[num[x]] = 0;
if(num[x] < n && vis[num[x] + 1] == 0)
num[x]++;
vis[num[x]] = 1;
}
// sort(num + 1, num + k + 1);
for(int i=1; i<=k; i++)
{
if(i != 1) cout << " ";
cout << num[i];
}
cout << endl;
return 0;
}
C - Robot Takahashi
考虑从小到大枚举所有可能的答案,因为从小到大,所以总共为找所有 \(f(x)\) 的代价也就是 \(O(n)\),每次 x 增加的时候,就从上一次的答案继续往下查找
我一开始以为相同重量的成年人和小孩没办法分辨,因此取了相邻重量的两个人的中间值作为枚举的答案,但是后来发现有点蠢了,直接枚举所有人的重量就可以了
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define pii pair<double, int>
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
string s;
cin >> n >> s;
vector<pii>a(n);
vector<double>b;
int ch = 0, ad = 0;
for(int i=0; i<n; i++)
{
int x;
cin >> x;
a[i] = {x, s[i] - '0'};
if(s[i] == '1') ad++;
}
sort(a.begin(), a.end());
b.push_back(-1);
for(int i=1; i<n; i++)
b.push_back((a[i].first + a[i].first) / 2);
b.push_back(1e9 + 10);
int ans = ad, tp = 0;
for(int i=0; i<b.size(); i++)
{
while(tp < n && a[tp].first < b[i])
{
if(a[tp].second == 1) ad--;
else ad++;
tp++;
}
ans = ad > ans ? ad : ans;
}
cout << ans << endl;
return 0;
}
D - Jumping Takahashi 2
dijkstra 或 Floyd 或 二分
dijkstra 枚举从每个点出发到所有点的最大代价的最小值
同理,Floyd 跑完之后再找这个最小值
二分答案,通过 bfs 判断是否有个点能跑遍历所有的点
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
#define pii pair<double, int>
const int maxn = 210;
const double eps = 1e-8;
ll gra[maxn][maxn];
int vis[maxn];
struct node
{
ll x, y, val;
node(){}
node(ll _x, ll _y, ll _v){x = _x; y = _y; val = _v;}
bool operator < (const node& a) const
{
return a.val < val;
}
}num[maxn];
ll dis(node& a, node& b)
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for(int i=1; i<=n; i++)
cin >> num[i].x >> num[i].y >> num[i].val;
for(int i=1; i<=n; i++)
{
for(int j=i+1; j<=n; j++)
{
ll s = dis(num[i], num[j]);
gra[i][j] = (s + num[i].val - 1) / num[i].val;
gra[j][i] = (s + num[j].val - 1) / num[j].val;
}
}
ll ans = 1e17 + 10;
for(int i=1; i<=n; i++)
{
for(int j=j=1; j<=n; j++) vis[j] = 0;
priority_queue<node>q;
q.push(node(i, i, 0));
ll temp = 0;
int cnt = n;
while(q.size() && cnt)
{
node now = q.top();
q.pop();
if(vis[now.y]) continue;
cnt--;
vis[now.y] = 1;
temp = max(temp, now.val);
for(int j=1; j<=n; j++)
if(vis[j] == 0)
q.push(node(now.y, j, gra[now.y][j]));
}
ans = min(ans, temp);
}
cout << ans << endl;
return 0;
}
E - Addition and Multiplication 2
首先要选个代价最小的,且价值最高,保证数字足够长
然后剩下的前就考虑如何从高位给数字“升级”,也就是枚举能够到的价值最高的数字
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
pii num[20];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for(int i=0; i<9; i++)
{
int x;
cin >> x;
num[i] = {x, -(i + 1)};
}
sort(num, num + 9);
for(int i=0; i<9; i++) num[i].second = -num[i].second;
int cnt = n / num[0].first;
int nn = n % num[0].first;
if(cnt == 0) cout << 0;
while(cnt && nn)
{
int way = num[0].second, ans = num[0].first + nn, x = 0;
for(int i=1; i<9; i++)
{
if(num[i].first <= ans && num[i].second > way)
{
way = num[i].second;
x = num[i].first;
}
}
if(way == num[0].second) break;
cout << way;
nn = nn - x + num[0].first;
cnt--;
}
while(cnt--) cout << num[0].second;
cout << endl;
return 0;
}
F - Teleporter Setting
bfs
先构建一个 0 号虚拟点,最后再遍历这个点是其他的点
答案有两种来源:
-
本身从 1 直接到达 n(可经过 0 号虚拟点)
-
经过 0 号虚拟点和当前假设的点 i 之间的代价为 0 的特殊边
对于第一种情况,只用计算最短路即可
对于第二种情况,则为 min(dis[1][0] + dis[i][n], dis[1][i] + dis[0][n])
综上,计算出 1 和 n 到其他所有点的最短路即可,然后枚举假设 0 号虚拟点为 i 号点,然后找最小的情况
我原本的写法比较笨,现在改用了上述这种写法
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <array>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 10;
const int inf = 1e8 + 10;
int n, m;
vector<int>gra[maxn];
vector<int> bfs(int s)
{
queue<array<int, 2> >q;
vector<int> dis(n + 1, inf);
q.push({s, 0});
while(q.size())
{
auto [x, d] = q.front();
q.pop();
if(dis[x] != inf) continue;
dis[x] = d;
for(auto i : gra[x])
if(dis[i] == inf) q.push({i, d + 1});
}
return dis;
}
int main()
{
cin >> n >> m;
for(int i=0; i<m; i++)
{
int x, y;
cin >> x >> y;
gra[x].push_back(y);
gra[y].push_back(x);
}
auto dis1 = bfs(1);
auto disn = bfs(n);
for(int i=1; i<=n; i++)
{
int ans = min({dis1[n], dis1[0] + disn[i], dis1[i] + disn[0]});
if(ans == inf) ans = -1;
if(i != 1) cout << " ";
cout << ans;
}
cout << endl;
return 0;
}