Codeforces Round #375 (Div. 2)
A. The New Year: Meeting Friends
题意:
有三个朋友都是住在Ox轴上,他们的地址分别为x1,x2,x3(1<=x1,x2,x3<=100,且三个数distinct),现在他们打算约一个地点(Ox轴上)见面,一起去庆祝新年,现求一个地点使得他们三个人分别到这个地点的距离之和最短。题目保证最优解为整数。
分析:
朴素求法。时间复杂度为O(1)。
代码如下:
#include <cstdio>
#include <cstring>
inline int MAX(int a, int b) {
return a > b ? a : b;
}
inline int MIN(int a, int b) {
return a < b ? a : b;
}
int main() {
//freopen("input.txt", "r", stdin);
int x_1, x_2, x_3;
while (~scanf("%d%d%d", &x_1, &x_2, &x_3)) {
int min_val = MIN(x_1, MIN(x_2, x_3));
int max_val = MAX(x_1, MAX(x_2, x_3));
printf("%d\n", max_val - min_val);
}
return 0;
}
B. Text Document Analysis
题意:
给出一个字符串,长度为n(1<=n<=255),这个字符串只由以下三种字符构成:
- 英文字母(大写或小写)
- 下划线(用来作为分隔符)
- 括号(包括左括号和右括号)
题目保证括号都是成对出现的,且每个右括号的之前字符中都存在左括号与之匹配,且每对括号里都不再存在另外一对括号,即括号不可嵌套,定义一个单词为连续出现的英文字母,现需求两个问题,一是求括号外最长单词的长度(如果括号外没有单词,则答案为0),二是求括号内的单词数(如果括号内没有单词,则答案为0)。
分析:
朴素求解。时间复杂度为O(n)。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <utility>
using namespace std;
const int maxn = 255 + 3;
char arr[maxn];
int n;
pair<int, int> solve() {
int ans_1 = 0, ans_2 = 0;
for (int i = 1; i <= n; ) {
if (arr[i] == '_') { ++i; continue; }
else if (arr[i] == '(') {
int idx = i + 1;
while (arr[idx] != ')') {
if (arr[idx] == '_') idx += 1;
else if (isalpha(arr[idx])) {
int ano_idx = idx;
while (isalpha(arr[ano_idx + 1])) ano_idx += 1;
ans_2 += 1;
idx = ano_idx + 1;
}
}
i = idx + 1;
}
else if (isalpha(arr[i])) {
int idx = i;
while (isalpha(arr[idx + 1])) idx += 1;
ans_1 = max(ans_1, idx - i + 1);
i = idx + 1;
}
}
return make_pair(ans_1, ans_2);
}
int main() {
//freopen("input.txt", "r", stdin);
memset(arr, 0, sizeof(arr));
while (~scanf("%d%s", &n, arr + 1)) {
pair<int, int> ans = solve();
printf("%d %d\n", ans.first, ans.second);
memset(arr, 0, sizeof(arr));
}
return 0;
}
C. Polycarp at the Radio
题意:
小明是个DJ,他手上现在有n首歌曲(1<=n<=2000),分别为a1,a2,...,an,ai(1<=ai<=10^9)表示的是乐队的编号,表示ai演奏第i首歌,小明喜欢的乐队是编号从1到m(1<=m<=2000)的乐队,定义bj为歌单中乐队j演奏的歌曲数目,现在小明想改变下歌单使得b1,..,bm中的最小数尽量大。求出这个数值,和需要改变歌单的最小次数。其中一次改变定义为将第i首歌的演奏者变为其他任意一个演奏者。
分析:
贪心。不难发现,那个尽量大的最小数即为n/m的下取整,将bj排序,那些小于ans的那些bj就是需要改变的对象,需要增加这些乐队的演奏曲目数。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
inline void read(int& buf) {
buf = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) {
buf = (buf << 3) + (buf << 1) + (c - '0');
c = getchar();
}
}
const int maxn = 2000 + 3;
int n, m, a[maxn], cnt[maxn], ans;
struct Node {
int idx, count;
Node(int aa, int bb): idx(aa), count(bb) {}
bool operator < (const Node& rhs) const {
return count > rhs.count;
}
};
vector<Node> good;
int solve() {
int change = 0, st = 0;
while (good.back().count < ans) {
Node buf = good.back(); good.pop_back();
int need = ans - buf.count, now = 0;
while (now < need) {
if (a[st] > m) { a[st] = buf.idx; now++; cnt[a[st++]]++; }
else if (cnt[a[st]] <= ans) st++;
else {
cnt[a[st]]--;
a[st] = buf.idx;
cnt[a[st++]]++;
now++;
}
}
change += need;
}
return change;
}
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
read(m);
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) {
read(a[i]);
if (a[i] >= 1 && a[i] <= m) cnt[a[i]]++;
}
ans = n / m;
good.clear();
for (int i = 1; i <= m; i++) good.push_back(Node(i, cnt[i]));
sort(good.begin(), good.end());
int change = solve();
printf("%d %d\n", ans, change);
for (int i = 1; i <= n; i++) {
if (i > 1) putchar(' ');
printf("%d", a[i]);
}
puts("");
}
return 0;
}
D. Lakes in Berland
题意:
一座小岛的地图是一个n*m(1<=n,m<=50)的长方形,其中每个单元都是一个1*1的小格,每个小格要么是陆地要么是水域,这座小岛的地图是被海洋环绕,湖就是连通的最大水域,但是却又不和海洋连通,正式来定义的话,就是,一个水域小格组成的集合,从这个集合中任意一个水域小格出发,只靠通过相连的边、不离开这个集合中的小格,都可到达集合中任意其他的水域小格,集合中的水域小格都不在矩形的边缘(因为那样便与海洋连通了),且这个集合已经包含了尽量多的水域小格,不然就还可以连通(添加)其他水域小格。你的任务是填上尽量少的水域小格,使得这座小岛上只有恰好k(0<=k<=50)个湖,注意到一开始小岛上的湖的数量不少于k。字符'.'表示水域小格,字符'*'表示陆地。
分析:
连通块+排序。找出图中所有的湖,假设一开始有k0个湖,填上水域格子数最少的k0-k个湖即可。时间复杂度为O(nm+k0*logk0)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;
const int maxn = 50 + 3;
char arr[maxn][maxn];
int n, m, k, cells;
vector<pair<int, int> > lake_cells[maxn * maxn];
bool already[maxn][maxn], flag;
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1};
struct Node {
int idx, cells;
Node(int aa, int bb): idx(aa), cells(bb) {}
bool operator < (const Node& rhs) const {
return cells < rhs.cells;
}
};
vector<Node> lakes;
inline bool is_in(int x, int y) {
return (x >= 0 && x < n && y >= 0 && y < m);
}
inline bool is_bound(int x, int y) {
return (x == 0 || x == n - 1 || y == 0 || y == m - 1);
}
int dfs(int x, int y, int idx) {
already[x][y] = true;
lake_cells[idx].push_back(make_pair(x, y));
int cnt = 1;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (!is_in(nx, ny) || arr[nx][ny] == '*' || already[nx][ny]) continue;
if (is_bound(nx, ny)) { flag = false; continue; }
cnt += dfs(nx, ny, idx);
}
return cnt;
}
void solve() {
for (int i = 0; i < n * m; i++) lake_cells[i].clear();
memset(already, 0, sizeof(already));
lakes.clear();
int total = -1;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (!is_bound(i, j) && !already[i][j] && arr[i][j] == '.') {
//printf("(%d,%d) ", i, j);
flag = true;
int cnt = dfs(i, j, ++total);
if (flag) lakes.push_back(Node(total, cnt));
else lake_cells[total--].clear();
//flag ? puts("ok") : puts("sorry");
}
//printf("#lakes is %d\n", total + 1);
sort(lakes.begin(), lakes.end());
int ans = 0;
for (int i = 0; i < total + 1 - k; i++) {
ans += lakes[i].cells;
const vector<pair<int, int> >& buf = lake_cells[lakes[i].idx];
int bound = buf.size();
for (int j = 0; j < bound; j++)
arr[buf[j].first][buf[j].second] = '*';
}
printf("%d\n", ans);
for (int i = 0; i < n; i++) puts(arr[i]);
}
int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
while (~scanf("%d%d%d", &n, &m, &k)) {
memset(arr, 0, sizeof(arr));
for (int i = 0; i < n; i++) scanf("%s", arr[i]);
solve();
}
return 0;
}