距离上次刷cf已经过去好久了吧,,
699A:Launch of Collider:
大概题意:
有一个有n个点的序列,序列中每一个点都有一个一维坐标以及移动方向,数据保证坐标是偶数,保证坐标升序给出,要求存在两个点相碰的最短时间
题解:
显然可以发现,相碰的两个点只可能是开始时相邻的两个点,而且一定保证左边的点的方向为”R”右边的点为”L”,那么直接扫一遍,对于可行的点对,用
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 200000 + 500;
const int inf = 0x7fffffff;
char s[maxn];
int x[maxn];
int n;
int ans = inf;
int main () {
scanf("%d", &n);
scanf("%s", s + 1);
for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
for (int i = 1; i <= n; i++) {
if (s[i] == 'R' && s[i+1] == 'L') {
ans = std :: min(ans, (x[i+1] - x[i]) / 2);
}
}
if (ans == inf) printf("-1");
else printf("%d", ans);
return 0;
}
699B:One Bomb:
大概题意:
对于一个n*m的地面,有若干个墙,其余点为空地,题目中给出一个炸弹,可以炸掉炸弹所在行和列的墙,炸弹可以放在地面上的任何位置,问能否用这一个炸弹使地面上没有墙,输出一个可行的位置,如果不能,输出”NO”
题解:
用fx[i]表示第i行的墙数,用fy[j]表示每列的墙数,记录总炸弹数为sumb,枚举炸弹的位置(i, j),每次check,如果
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 1200;
int mapp[maxn][maxn];
char c;
int n, m;
int sumb;
int fx[maxn], fy[maxn];
bool check(int x, int y) {
int cur = fx[x] + fy[y];
if (mapp[x][y] == 1) cur--;
if (cur == sumb) return 1;
return 0;
}
int main () {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
getchar();
for (int j = 1; j <= m; j++) {
c = getchar();
if (c == '*') {
sumb++;
fx[i]++;
fy[j]++;
mapp[i][j] = 1;
}
}
}
// for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= m; j++) printf("%d", mapp[i][j]);
// printf("\n");
// }
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (check(i, j)){
printf("YES\n%d %d", i, j);
exit(0);
}
}
printf("NO");
return 0;
}
699C Vacations:
为什么感觉C题比B题还水呢,,,
大概题意:
题中人有运动和在线比赛两种选择,而对于某一天,有四种可能:
- 不能操作
- 可以运动
- 可以比赛
- 可以运动和比赛
题中人不能在相邻的两天进行相同操作(即,如果第3天进行了运动,第4天就不能进行运动)
题解:
显然是个dp题目咯=。=
设dp[i][j]表示在第i天,当前天选择了j操作时的最小值
j = 0表示休息,j = 1表示运动 j = 2,表示比赛
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 150;
int dp[maxn][3]; // 0 rest 1 sport 2 contest
int n;
int a[maxn];
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memset(dp, 127, sizeof(dp));
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
if (a[i] == 0)
for (int j = 0; j <= 2; j++)
dp[i][0] = std :: min(dp[i-1][j] + 1, dp[i][0]);
if (a[i] == 1) {
for (int j = 0; j <= 2; j++)
dp[i][0] = std :: min(dp[i-1][j] + 1, dp[i][0]);
dp[i][2] = std :: min(dp[i-1][0], dp[i][2]);
dp[i][2] = std :: min(dp[i-1][1], dp[i][2]);
}
if (a[i] == 2) {
for (int j = 0; j <= 2; j++)
dp[i][0] = std :: min(dp[i-1][j] + 1, dp[i][0]);
dp[i][1] = std :: min(dp[i-1][0], dp[i][1]);
dp[i][1] = std :: min(dp[i-1][2], dp[i][1]);
}
if (a[i] == 3) {
for (int j = 0; j <= 2; j++)
dp[i][0] = std :: min(dp[i-1][j] + 1, dp[i][0]);
dp[i][1] = std :: min(dp[i-1][0], dp[i][1]);
dp[i][1] = std :: min(dp[i-1][2], dp[i][1]);
dp[i][2] = std :: min(dp[i-1][0], dp[i][2]);
dp[i][2] = std :: min(dp[i-1][1], dp[i][2]);
}
}
int ans = 0x7fffffff;
for (int j = 0; j <= 2; j++) ans = std :: min(ans, dp[n][j]);
printf("%d", ans);
return 0;
}
699D :Fix a Tree
简要题意:
题目中给定一个n和数组father,其中father[i]表示i的父亲节点,题目中定义可构成一棵树的father数组为可行数组,要求修改father数组,使之成为一个可行数组,输出最小的修改次数以及任意一个修改方案
题解:
- 不难发现这张图将会由多个章鱼图(即n个点n条边的基环树)和树构成
- 既然题目要求使最后形成一棵树,那么一定同时满足联通和无环
- 首先考虑无环,对于一个章鱼图,可以随意拆掉环上的任何一个点,并把它的father值修改,对于一棵树则无需修改
- 考虑联通,如果想让两棵树联通,那么只需将其中一棵的根节点的father置为另一棵,如果有环的话,将环上任意一点的father值设为另一棵的根节点,如果是两个基环树,则需要将其中一个的father置为本身,另一个置为该值
- 综上,先对图进行tarjan,如果结果中没有树,则ans=环的数量,否则ans=环的数量+树的数量-1
- 对于方案,如果没有树,则从任意环中取出一个节点,以之为根,从其他所有环中各取一点与其相连。如果有树,则以某一棵树的根为总根,另其他树和环都与之相连,此时的father数组即为答案
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 200000 + 5000;
int n;
int a[maxn];
int last[maxn], pre[maxn], other[maxn];
int tot = 1;
int dfn[maxn], low[maxn], sta[maxn];
bool vis[maxn];
int statot = 0;
int cur = 0;
int belong[maxn];
int point[maxn]; // if k is a cycle then make point[k] connect to the root
int tim = 0;
int size[maxn];
void tarjan(int x) {
tim++;
dfn[x] = low[x] = tim;
statot++;
sta[statot] = x;
vis[x] = 1;
for (int p = last[x]; p; p = pre[p]) {
int q = other[p];
if (!dfn[q]) {
tarjan(q);
low[x] = std :: min(low[x], low[q]);
} else if (vis[q]) {
low[x] = std :: min(low[x], dfn[q]);
}
}
if (dfn[x] == low[x]) {
cur++;
while (sta[statot] != x) {
vis[sta[statot]] = 0;
size[cur]++;
belong[sta[statot]] = cur;
statot--;
}
statot--;
belong[x] = cur;
vis[x] = 0;
size[cur]++;
point[cur] = x;
}
}
void add(int x, int y) {
tot++;
pre[tot] = last[x];
last[x] = tot;
other[tot] = y;
}
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
add(a[i], i);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
int ans = 0;
int ansk = 0;
for (int i = 1; i <= cur; i++) {
if (size[i] == 1) {
if (a[point[i]] == point[i]) {
ans++;
ansk = point[i];
}
} else {
ans++;
}
}
if (ansk > 0) ans--;
printf("%d\n", ans);
if (ansk == 0) {
for (int i = 1; i <= cur; i++)
if (size[i] > 1) {
ansk = point[i];
break;
}
}
for (int i = 1; i <= cur; i++) {
if (size[i] == 1 && a[point[i]] != point[i]) continue;
a[point[i]] = ansk;
}
for (int i = 1; i <= n; i++) printf("%d ", a[i]);
return 0;
}