A
最近的RL之间距离的一半。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;
const int INF = 1e9 + 10;
char str[2 * MAXN];
int a[2 * MAXN];
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
scanf("%s", str);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int ans = INF;
for(int i = 0; i < n-1; i++) {
if(str[i] == 'R' && str[i+1] == 'L') {
ans = min(ans, (a[i+1] - a[i]) / 2);
i++;
}
}
printf(ans != INF ? "%d\n" : "-1\n", ans);
}
return 0;
}
题意:在某个位置放一个炸弹,可以消除该行该列的所有*。
问可不可以只放置一个炸弹,便可去掉矩阵中所有的*,输出放置的位置。
思路:只要确定图中所有*都在某一个行或者某一列上即可。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;
const int INF = 1e9 + 10;
char str[1001][1001];
int row[1001], cul[1001];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 0; i < n; i++) {
scanf("%s", str[i]);
}
CLR(row, 0); CLR(cul, 0);
int sum = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
row[i] += str[i][j] == '*';
sum += str[i][j] == '*';
}
}
for(int j = 0; j < m; j++) {
for(int i = 0; i < n; i++) {
cul[j] += str[i][j] == '*';
}
}
bool flag = false;
int x, y;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(row[i] + cul[j] - (str[i][j] == '*') == sum) {
flag = true;
x = i, y = j;
}
}
}
if(flag) {
printf("YES\n");
printf("%d %d\n", x + 1, y + 1);
}
else {
printf("NO\n");
}
}
return 0;
}
C
水题没法说,用dp写的。
dp[i][0]
表示第i天休息前i天的最优解
dp[i][1]
表示第i天运动前i天的最优解
dp[i][2]
表示第i天练习前i天的最优解
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;
const int INF = 1e9 + 10;
int dp[1001][3];
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
CLR(dp, INF);
dp[0][0] = dp[0][1] = dp[0][2] = 0;
for(int i = 1; i <= n; i++) {
int v; scanf("%d", &v);
dp[i][0] = min(min(dp[i-1][0], dp[i-1][1]), dp[i-1][2]) + 1;
if(v == 2 || v == 3) {
dp[i][1] = min(dp[i-1][0], dp[i-1][2]);
}
if(v == 1 || v == 3) {
dp[i][2] = min(dp[i-1][0], dp[i-1][1]);
}
}
printf("%d\n", min(min(dp[n][0], dp[n][1]), dp[n][2]));
}
return 0;
}
D
题意:给定n个节点以及各自的信息——父亲节点a[],让你修改最少的点信息,使得这n个点构成一棵树。
思路:给定a[i] == i的情况,就选择其中一个作为root,然后用并查集统计联通块数目。若已经确定root,就直接把其他块的根节点连到root上。没有确定的话,随便选择一个联通块的根节点作为root即可,其它的根节点连到root上。唯一不同的是——前一种情况确定了一条包含root的链,而后一种全是环。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;
const int INF = 1e9 + 10;
int f[2 * MAXN];
int a[2 * MAXN];
int Find(int p) {
int child = p, t;
while(p != f[p]) { p = f[p]; }
while(child != p) { t = f[child]; f[child] = p; child = t; }
return p;
}
void Merge(int x, int y) {
int fx = Find(x);
int fy = Find(y);
if(fx != fy) f[fx] = fy;
}
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) {
f[i] = i;
}
int root = -1; int cnt = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if(a[i] == i) {
if(root == -1) root = i;
else {
a[i] = root; cnt++;
}
}
Merge(i, a[i]);
}
for(int i = 1; i <= n; i++) {
if(f[i] == i) {
cnt++;
}
}
if(root != -1) {
printf("%d\n", cnt - 1);
for(int i = 1; i <= n; i++) {
if(f[i] == i && i != root) {
a[i] = root;
}
}
}
else {
printf("%d\n", cnt);
for(int i = 1; i <= n; i++) {
if(f[i] == i) {
root = i; a[i] = i; break;
}
}
for(int i = 1; i <= n; i++) {
if(f[i] == i && i != root) {
a[i] = root;
}
}
}
for(int i = 1; i <= n; i++) {
if(i > 1) printf(" ");
printf("%d", a[i]);
}
printf("\n");
}
return 0;
}