A. Nicholas and Permutation(Codeforces 676A)
思路
显然,将最大值或最小值中的一个交换到数组的某一端(若不放在端点上,则放在更靠近端点的位置总能得到更优的解)能让最大值与最小值之间的距离最大。我们可以通过计算计算出最优的方法。但是因为只有四种组合(最小值最左,最小值最右,最大值最左,最大值最右),所以可以直接枚举组合,并更新最优解。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 110;
int n, b, c, minIdx, maxIdx, a[maxn];
int abs(int x) {
return x > 0 ? x : -x;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if(a[i] == 1) {
minIdx = i;
}
if(a[i] == n) {
maxIdx = i;
}
}
b = max(abs(minIdx - n), abs(minIdx - 1));
c = max(abs(maxIdx - n), abs(maxIdx - 1));
printf("%d\n", max(b, c));
return 0;
}
B.Pyramid of Glasses(Codeforces 676B)
思路
因为 n≤10 ,所以酒杯的数量 num≤55 (等差数列求和)。这样的数量足以让我们用暴力的方法解决此题。首先最暴力的办法是每次往最顶端的酒杯倒一杯酒,然后就循环或递归访问每个酒杯,以计算出每个酒杯的酒的余量。其次比较不那么暴力的方法是一次性把所有的酒倒进最顶端的酒杯中,然后也是循环或递归访问每个酒杯,以计算出每个酒杯的余量。显然,相比之下,不论在时间复杂度还是在实现复杂度上,后者会优于前者。但前者更容易被想到。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 15;
const double eps = 1e-10;
int n, t, cnt;
double h[maxn][maxn];
int cmp(double x) {
return x < - eps ? -1 : x > eps;
}
void dfs(int x, int y, double come) {
if(x > n) {
return;
}
if(cmp(come) == 0) {
return;
}
if(cmp(h[x][y] - 1) == 0) {
dfs(x + 1, y, come / 2);
dfs(x + 1, y + 1, come / 2);
}
else {
if(cmp(h[x][y] + come - 1) < 0) {
h[x][y] += come;
}
else {
int to = h[x][y] + come - 1;
cnt++;
h[x][y] = 1;
dfs(x + 1, y, to / 2);
dfs(x + 1, y + 1, to / 2);
}
}
}
int main() {
scanf("%d%d", &n, &t);
cnt = 0;
while(t--) {
dfs(1, 1, 1.0);
}
printf("%d\n", cnt);
return 0;
}
C. Vasya and String(Codeforces 676C)
思路
刚开始一直往动态规划那方面想,所以浪费了不少时间。但实际上本题从“枚举子串”的方面想才是对的(看来凡事还是先上暴力思维会比较不容易走偏)。我们可以先以
O(n2)
的复杂度枚举出子串,然后以
O(n)
的复杂度计算出该子串是否能通过
k
次“改变”变成字符统一的字符串。在枚举中更新满足条件的子串的最大长度即可。但是
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
char s[maxn];
int n, k, l, r, sa, sb, ans = 0;
int main() {
scanf("%d%d%s", &n, &k, s);
sa = (s[l=0] == 'a');
sb = (s[r=0] == 'b');
while(r < n) {
if(sa <= k || sb <= k) {
ans = max(ans, r - l + 1);
}
else {
sa -= (s[l] == 'a');
sb -= (s[l++] == 'b');
}
sa += (s[++r] == 'a');
sb += (s[r] == 'b');
}
printf("%d\n", ans);
return 0;
}
D. Theseus and labyrinth(Codeforces 676D)
思路
若没有方块的旋转,则这个问题就是简单的用
代码
#include <bits/stdc++.h>
using namespace std;
// 搜索树中的节点
struct node {
int x, y, s, d;
node(int x, int y, int s, int d): x(x), y(y), s(s), d(d) {}
};
const int maxn = 1010;
// 上右下左四个方向的坐标变化
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
// 判重用的数组
bool vis[maxn][maxn][5];
char G[maxn][maxn];
int n, m, sx, sy, tx, ty, b[150];
queue <node> q;
// 初始化映射
void init() {
b['^'] = 1 << 0;
b['>'] = 1 << 1;
b['v'] = 1 << 2;
b['<'] = 1 << 3;
b['L'] = ~b['<'];
b['R'] = ~b['>'];
b['U'] = ~b['^'];
b['D'] = ~b['v'];
b['-'] = b['<'] | b['>'];
b['|'] = b['^'] | b['v'];
b['+'] = b['|'] | b['-'];
}
// 状态的转移
void expand(node& u, int dir) {
int x, y, s, d, i, j;
if(dir == -1) {
x = u.x;
y = u.y;
s = (u.s + 1) % 4;
d = u.d + 1;
if(vis[x][y][s]) {
return;
}
q.push(node(x, y, s, d));
vis[x][y][s] = true;
}
else {
// 判断本方块往dir方向是否有通路
i = b[G[u.x][u.y]];
j = 1 << ((dir - u.s + 4) % 4);
if((i & j) == 0) {
return;
}
x = u.x + dx[dir];
y = u.y + dy[dir];
s = u.s;
d = u.d + 1;
// 防止访问越界
if(x < 1 || x > n || y < 1 || y > m) {
return;
}
// BFS的判重
if(vis[x][y][s]) {
return;
}
// 判断新方块的dir方向的反方向是否有通路
i = b[G[x][y]];
j = 1 << ((dir + 2 - s + 4) % 4);
if((i & j) == 0) {
return;
}
q.push(node(x, y, s, d));
vis[x][y][s] = true;
}
}
int bfs(node s) {
q.push(s);
while(!q.empty()) {
node u = q.front();
q.pop();
if(u.x == tx && u.y == ty) {
return u.d;
}
// 共有5种方式向BFS的队列加入新的节点
// 0, 1, 2, 3分别表示上右下左4个方向
// -1表示所有的方块顺时针方向旋转90度
for(int i = -1; i < 4; i++) {
expand(u, i);
}
}
return -1;
}
int main() {
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%s", G[i] + 1);
}
scanf("%d%d%d%d", &sx, &sy, &tx, &ty);
vis[sx][sy][0] = true;
printf("%d\n", bfs(node(sx, sy, 0, 0)));
return 0;
}
(其它题目略)