AtCoder Beginner Contest 325
B - World Meeting
难度: ⭐
题目大意
一家公司在全球多地都有分公司; 现在总公司想选择一个时间点让所有公司都来开会; 但是每个公司的上班时间是 9:00-18:00; 给定每个公司的人数和相对于总公司的时差, 会议持续一个小时, 请问总公司最多能让多少人参加会议
解题思路
因为数据范围很小, 所以可以直接暴力;
神秘代码
#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;
typedef pair<int, int> PII;
int n, m, idx;
int w[N], x[N];
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> w[i] >> x[i];
}
for(int i = 0; i < 24; i++){
int l = i, r = l + 1;
int res = 0;
for(int j = 1; j <= n; j++){
int a = (l + x[j]) % 24, b = (r + x[j]) % 24;
if(a == 23) b = 24;
if(a >= 9 && b <= 18) res += w[j];
}
idx = max(idx, res);
}
cout << idx;
return 0;
}
C - Sensors
难度: ⭐⭐
题目大意
给定一个由'.'和'#'组成的字符矩阵; 请问该矩阵中有多少个'#'块; 对于一个'#', 与其水平、垂直或对角相邻方格中的'#'同属于一个块;
解题思路
一个简单的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 = 2e3 + 10;
typedef pair<int, int> PII;
int n, m, idx;
char g[N][N];
bool st[N][N];
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
void bfs(int i, int j){
queue<PII> q;
q.push({i, j});
st[i][j] = true;
while(q.size()){
PII t = q.front();
q.pop();
for(int i = 0; i < 8; i++){
int x = t.first + dx[i], y = t.second + dy[i];
if(x >= 1 && x <= n && y >=1 && y <= m && g[x][y] == '#' && !st[x][y]){
q.push({x, y});
st[x][y] = true;
}
}
}
}
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> g[i][j];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(!st[i][j] && g[i][j] == '#'){
bfs(i, j);
idx++;
}
}
}
cout << idx;
return 0;
}
D - Printing Machine
难度: ⭐⭐
题目大意
现在有一个传送带, 有一个工人每秒可以处理一个零件; 现在给出n个零件进入传送带的时间t, 以及该零件在传送带的停留时间d; 请问工人该如何操作才能最终处理尽可能多的零件, 输出最大零件数;
解题思路
一道比较明显的贪心加排序; 先把每个零件出传送带的时间算出来: t + d, 我们可以把所有零件按照进入传送带的时间排序, 然后我们用堆来按照离开传送带的时间从小到大维护, 如果进入时间小于等于当前时间, 那么就可以把该零件放进堆里; 每次优先处理当前最早离开传送带的零件; 如果堆中还有零件那么当前时间每次只能+1; 如果没有了就可以直接跳到下一个最早进入传送带的零件的进入时间;
神秘代码
#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;
typedef pair<int, int> PII;
int n, m, idx;
int t[N], d[N];
struct Node{
int t, d;
}stu[N];
bool cmp(Node a, Node b){
return a.t < b.t;
}
priority_queue<int, vector<int>, greater<int>> heap;
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> stu[i].t >> stu[i].d;
stu[i].d += stu[i].t;
}
sort(stu + 1, stu + 1 + n, cmp);
int i = 1;
for(; i <= n; i++){
if(stu[i].t == stu[1].t){
heap.push(stu[i].d);
}
else break;
}
int now = stu[1].t;
while(heap.size()){
while(i <= n && stu[i].t <= now) {
heap.push(stu[i++].d);
}
while(heap.size() && heap.top() < now){
heap.pop();
}
if(heap.empty()){
if(i <= n){
now = stu[i].t;
heap.push(stu[i++].d);
}
}
else{
idx++;
heap.pop();
if(heap.size()) now++;
else if(i <= n){
now = stu[i].t;
heap.push(stu[i++].d);
}
}
}
cout << idx;
return 0;
}
E - Our clients, please wait a moment
难度: ⭐⭐⭐
题目大意
小莫想从城市1出发到达城市n; 给出每个城市之间的距离d; 出行方式有两种: 汽车或者火车; 如果是汽车, 那么经过一条路径所需要的时间为d * a; 如果是火车, 那么经过一条路径所需要的时间为d * b + c; 小莫可以在中途某个城市将汽车改为火车, 但不能反过来; 请问小莫最少需要多长时间可以到达城市n;
解题思路
思路是最短路加dp; 汽车和火车之间的转换明显可以通过dp来完成; 并且不管是汽车还是火车, 其时间还是与道路距离成正比; 所以我们可以用堆优化的最短路来实现, 更新时间时更新两种, 分别是汽车和火车; dp[1][x]表示火车, dp[0][x]表示汽车; 状态转移题目已经给了;
神秘代码
#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 = 2e3 + 10;
typedef pair<int, int> PII;
int n, m, idx;
int a, b, c;
int g[N][N], dp[2][N], d[N];
bool st[N];
int solve(){
priority_queue<PII, vector<PII>, greater<PII>> heap;
for(int i = 1; i <= n; i++) {
dp[1][i] = dp[0][i] = 1e16;
}
dp[1][1] = dp[0][1] = 0;
heap.push({0, 1});
while(heap.size()){
PII t = heap.top();
heap.pop();
int v = t.second;
for(int i = 1; i <= n; i++){
if(g[v][i]){
if(dp[0][i] > dp[0][v] + g[v][i] * a){
dp[0][i] = dp[0][v] + g[v][i] * a;
heap.push({dp[0][i], i});
}
if(dp[1][i] > min(dp[1][v], dp[0][v]) + g[v][i] * b + c){
dp[1][i] = min(dp[1][v], dp[0][v]) + g[v][i] * b + c;
heap.push({dp[1][i], i});
}
}
}
}
return min(dp[1][n], dp[0][n]);
}
signed main(){
cin >> n >> a >> b >> c;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cin >> g[i][j];
}
}
cout << solve();
return 0;
}
F - Sensor Optimization Dilemma
难度: ⭐⭐⭐⭐
题目大意
公安部想要监控一条街道的几个区段, 一共有n个路段, 其中第i个路段的长度为d1; 有两种监控可以选择, 1/2型监控: 可监控的长度为l1 / l2的路段, 每个监控的价格为c1 / c2, 最多可以使用k1 / k2个此类监控; 注意: 即使两个监控的监控范围重叠或者监控范围超出路段范围也没有问题, 最后只要保证这n个路段都能被监控到就选; 确定是否可以监控这n个路段, 如果可以则输出最低成本;
解题思路
算是比较明显的dp, 这道dp的难点主要在于状态表示; dp[i][j]表示在前i个路段一共使用j个1型监控时所需要的2型监控的最少数量; 对于当前第i个路段, 我们可以遍历k (0 <= k <= j), 表示第i个路段使用了多少个1型传感器, 因此dp[i][j]就可以从dp[i - 1][j - k]转移而来; 并且由k我们就能知道第i个路段还有max(0, di - k * l1)的长度没有被监控, 根据这个长度来确定至少需要多少个2型监控, 其数量就是max(0, di - k * l1) / l2, 小数向上取整即可; 最后找答案时只要dp[n][j]的数量小于等于k2就说明满足情况, 然后去计算成本就可以了;
神秘代码
#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 = 2e2 + 10;
typedef pair<int, int> PII;
int n, m, idx;
int d[110];
int dp[110][1010];
int l1, l2, c1, c2, k1, k2;
signed main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> d[i];
}
cin >> l1 >> c1 >> k1 >> l2 >> c2 >> k2;
memset(dp, 0x3f, sizeof dp);
for(int i = 0; i <= k1; i++){
dp[1][i] = (int)ceil(1.0 * max(0ll, d[1] - i * l1) / l2);
}
for(int i = 2; i <= n; i++){
for(int j = 0; j <= k1; j++){
for(int k = 0; k <= j; k++){
dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + (int)ceil(1.0 * max(0ll, d[i] - l1 * k) / l2));
}
}
}
int res = 1e15;
for(int i = 0; i <= k1; i++){
if(dp[n][i] <= k2){
res = min(res, i * c1 + dp[n][i] * c2);
}
}
if(res == 1e15) res = -1;
cout << res;
return 0;
}