#51nod上topcoder练习记
好久没刷51nod了,又听说topcoder有很多好题。那么就来51nod上刷吧。(那个客户端搞得有点烦(看不懂))
当图不连通的时候,答案为无穷大。
当图连通时,两个点之间的最大差值就是最短路长度乘上 $d$,跑floyd再看最短路的最大值即可。
1 #include <bits/stdc++.h> 2 3 const int N = 55; 4 const int INF = 0x3f3f3f3f; 5 6 char s[N]; 7 int mp[N][N], fa[N], n; 8 9 int getfa(int x) { 10 return x == fa[x] ? x : fa[x] = getfa(fa[x]); 11 } 12 13 void unit(int x, int y) { 14 x = getfa(x), y = getfa(y); 15 fa[x] = y; 16 } 17 18 void floyd() { 19 for (int k = 1; k <= n; k++) 20 for (int i = 1; i <= n; i++) 21 for (int j = 1; j <= n; j++) 22 mp[i][j] = std::min(mp[i][j], mp[i][k] + mp[k][j]); 23 } 24 25 int main() { 26 int T; 27 scanf("%d", &T); 28 while (T--) { 29 int d; 30 scanf("%d%d", &n, &d); 31 for (int i = 1; i <= n; i++) fa[i] = i; 32 for (int i = 1; i <= n; i++) { 33 scanf("%s", s + 1); 34 for (int j = 1; j <= n; j++) { 35 if (s[j] == 'Y' && i != j) 36 mp[i][j] = d, unit(i, j); 37 else if (i != j) 38 mp[i][j] = INF; 39 else 40 mp[i][j] = 0; 41 } 42 } 43 int cnt = 0; 44 for (int i = 1; i <= n; i++) 45 if (getfa(i) == i) cnt++; 46 if (cnt > 1) { 47 puts("-1"); 48 continue; 49 } 50 floyd(); 51 int ans = 0; 52 for (int i = 1; i <= n; i++) 53 for (int j = 1; j <= n; j++) 54 if (mp[i][j] < INF) 55 ans = std::max(ans, mp[i][j]); 56 printf("%d\n", ans); 57 } 58 return 0; 59 }
可以发现当限制比数字的位置还大时,这个限制就没用了。
然后有时候到不了极限数据,因为被前面的卡住了或者被后面的卡住了。
即 $t_i - t_{i - 1} > x_i - x_{i - 1}$,$t_i - t_{i + 1} > x_{i + 1} - x_i$ 这两种情况。暴力更新即可。
然后最大值就在每两个限制之间得到。
#include <bits/stdc++.h> const int N = 55; int x[N], t[N]; int main() { int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d%d", &n, &m); int cnt = 1; x[cnt] = 1, t[cnt] = 0; for (int i = 1; i <= m; i++) { int a, b; scanf("%d%d", &a, &b); if (b < a - 1) x[++cnt] = a, t[cnt] = b; } if (!cnt) { printf("%d\n", n - 1); continue; } for (int i = 1; i <= cnt; i++) { if (i > 1 && t[i] - t[i - 1] > x[i] - x[i - 1]) t[i] = t[i - 1] + x[i] - x[i - 1]; if (i < cnt && t[i] - t[i + 1] > x[i + 1] - x[i]) { t[i] = t[i + 1] + x[i + 1] - x[i]; i = 0; } } int ans = 0; for (int i = 1; i < cnt; i++) ans = std::max(ans, (t[i] + t[i + 1] - x[i] + x[i + 1]) / 2); ans = std::max(ans, t[cnt] + n - x[cnt]); printf("%d\n", ans); } }
一种球的贡献最多为 $2$,那么统计球的个数即可。
#include <bits/stdc++.h> const int N = 60; char s[N]; int cnt[3]; inline int getid(char ch) { if (ch == 'R') return 0; if (ch == 'G') return 1; return 2; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%s", s + 1); int n = strlen(s + 1); if (n == 1) { puts("0"); continue; } if (n == 2) { puts("1"); continue; } for (int i = 0; i < 3; i++) cnt[i] = 0; for (int i = 1; i <= 2; i++) cnt[getid(s[i])]++; int ans = 1; for (int i = 3; i <= n; i++) { for (int j = 0; j < 3; j++) ans += std::min(cnt[j], 2); cnt[getid(s[i])]++; } printf("%d\n", ans); } return 0; }
和一个点会有交集的点最多只有 $k^2$ 个,特判这些点,再去其他点中最大的那个即可。
#include <bits/stdc++.h> #define pii pair<int, int> #define fi first #define se second const int N = 110; const int M = 1e4 + 7; int dx[11], dy[11]; char s[N]; int mp[N][N]; std::vector<int> belong[M]; std::pii p[M]; std::map<std::pii, int> gong; int main() { freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while (T--) { int n, m, k; scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= n; i++) { scanf("%s", s + 1); for (int j = 1; j <= m; j++) mp[i][j] = s[j] - '0'; } for (int i = 1; i <= k; i++) scanf("%d%d", &dx[i], &dy[i]); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int pos = (i - 1) * m + j; p[pos].se = pos; p[pos].fi = 0; for (int z = 1; z <= k; z++) { int x = i + dx[z], y = j + dy[z]; if (x <= 0 || x > n || y <= 0 || y > m) continue; belong[(x - 1) * m + y].push_back(pos); p[pos].fi += mp[x][y]; } } int ans = 0; std::sort(p + 1, p + n * m + 1, std::greater<std::pii>()); for (int cnt = 1; cnt <= n * m; cnt++) { gong.clear(); int pos = p[cnt].se; int i = pos / m, j = pos % m; if (!j) j = m; else i++; if (p[cnt].fi + p[1].fi <= ans) continue; for (int z = 1; z <= k; z++) { int x = i + dx[z], y = j + dy[z]; if (x <= 0 || x > n || y <= 0 || y > m) continue; int ne = (x - 1) * m + y; for (int tong: belong[ne]) { if (pos == tong) continue; gong[std::pii(std::min(pos, tong), std::max(pos, tong))] -= mp[x][y]; } } for (int z = 1; z <= k * k + 1; z++) { if (z == cnt) continue; int id = p[z].se; ans = std::max(ans, gong[std::pii(std::min(pos, id), std::max(pos, id))] + p[cnt].fi + p[z].fi); if (!gong.count(std::pii(std::min(pos, id), std::max(pos, id)))) break; } } for (int i = 1; i <= n * m; i++) belong[i].clear(), p[i].fi = p[i].se = 0; printf("%d\n", ans); } return 0; }
唉,这都想不出来,好菜啊...
$i$ 到 $j$ 的代价就等于第 $i$ 行 $0$ 到 $j - 1$ 有多少个 'Y'。要优先走这条边就要付出这么多代价,然后floyd就好了
#include <bits/stdc++.h> const int N = 55; const int INF = 0x3f3f3f3f; int mp[N][N]; char s[N]; int main() { int T; scanf("%d", &T); while (T--) { memset(mp, 0x3f, sizeof mp); int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", s + 1); int cost = 0; for (int j = 1; j <= n; j++) if (s[j] == 'Y') mp[i][j] = cost++; } for (int i = 1; i <= n; i++) mp[i][i] = 0; for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) mp[i][j] = std::min(mp[i][j], mp[i][k] + mp[k][j]); printf("%d\n", mp[1][n] == INF ? -1 : mp[1][n]); } return 0; }
当取的 $low$ 值之和不小于 $x$ 时,为一个方案
当不取的 $high$ 值之和不大于 $c - x$ 时,为一个方案
这两种情况可以独立来算,对 $low$ 和 $high$ 分别排个序就ok了。
#include <bits/stdc++.h> const int N = 55; int low[N], high[N]; int main() { //freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while (T--) { int n, c, x; scanf("%d%d%d", &n, &c, &x); for (int i = 1; i <= n; i++) scanf("%d%d", low + i, high + i); int ans = n; std::sort(low + 1, low + 1 + n); std::sort(high + 1, high + 1 + n); for (int i = n, sum = 0; i; i--) { sum += low[i]; if (sum >= x) { ans = std::min(n - i + 1, ans); break; } } for (int i = 1, sum = 0; i <= n; i++) { sum += high[i]; if (c - sum < x) { ans = std::min(ans, n - i + 1); break; } } printf("%d\n", ans); } return 0; } /*** 34 32 28 ***/
当不出现问号时,该开时开,该关时关就OK了。
当出现了问号时,如果上一轮的该位置状态为 '-' 且这一轮有开灯的操作,那么这一位就可以是 '?',或者该位置状态为 '+' 且这一轮有关灯的操作,同理也是 '?'
多一个 '?' 就可以让之后尽量少操作。
#include <bits/stdc++.h> const int N = 55; char mp[N][N], s[N]; int main() { int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1); for (int i = 1; i <= m; i++) s[i] = '-'; int ans = 0; for (int i = 1; i <= n; i++) { bool open = 0, close = 0; for (int j = 1; j <= m; j++) { if (s[j] == '-' && mp[i][j] == '+') open = 1; if (s[j] == '+' && mp[i][j] == '-') close = 1; } if (open) ans++; if (close) ans++; ans++; for (int j = 1; j <= m; j++) { if (mp[i][j] == '?') { if (close && s[j] == '+') s[j] = '?'; if (open && s[j] == '-') s[j] = '?'; } else { s[j] = mp[i][j]; } } } printf("%d\n", ans); } return 0; }
答案最多为 3,为 3 时即存在奇环,bfs判一下即可。
#include <bits/stdc++.h> const int N = 77; const int dir[6][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 0}, {1, -1}, {0, -1}}; char s[N][N]; int n, dis[N][N]; bool bfs(int dx, int dy) { std::queue< std::pair<int, int> > que; que.push(std::pair<int, int>(dx, dy)); while (!que.empty()) { std::pair<int, int> p = que.front(); que.pop(); int i = p.first, j = p.second; for (int k = 0; k < 6; k++) { int x = i + dir[k][0], y = j + dir[k][1]; if (x < 1 || y < 1 || x > n || y > n || s[x][y] == '-') continue; if (dis[x][y]) { if (dis[x][y] % 2 == dis[i][j] % 2) return true; continue; } que.push(std::pair<int, int>(x, y)); dis[x][y] = dis[i][j] + 1; } } return false; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%d", &n); int ans = 0; for (int i = 1; i <= n; i++) { scanf("%s", s[i] + 1); for (int j = 1; j <= n; j++) if (s[i][j] == 'X') ans = 1; } for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (s[i][j] == 'X') { for (int k = 0; k < 6; k++) { int x = i + dir[k][0], y = j + dir[k][1]; if (x < 1 || y < 1 || x > n || y > n || s[x][y] == '-') continue; ans = 2; } } memset(dis, 0, sizeof(dis)); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (s[i][j] == 'X' && dis[i][j] == 0) if (bfs(i, j)) ans = 3; printf("%d\n", ans); } return 0; }

浙公网安备 33010602011771号