博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces Round #286 (Div. 1) 解题报告
阅读量:7099 次
发布时间:2019-06-28

本文共 3583 字,大约阅读时间需要 11 分钟。

A.

     很显然的一个DP,30000的数据导致使用map+set会超时。题解给了一个非常实用的做法,由于每个点有不超过250种状态,并且这些状态都是以包含d连续的一段数字,那么可以以对d的偏移量作为状态。这算是很常见的一个优化了。

#include
using namespace std;const int INF = 30009;int f[INF][500],a[INF];int n, d, ans = 1, x;int main() { scanf ("%d %d", &n, &d); for (int i = 1; i <= n; i++) { scanf ("%d", &x); a[x]++; } f[d][250] = a[d] + 1; for (int i = d; i <= x; i++) for (int j = 0; j < 500; j++) { if (f[i][j] == 0) continue; int k = j - 250 + d, val = f[i][j]; ans = max (ans, val); for (int t = max (1, k - 1); t <= k + 1; t++) if (i + t <= x) f[i + t][t - d + 250] = max (f[i + t][t - d + 250], val + a[i + t]); } printf ("%d\n", ans - 1);}
View Code

 

 

B.

     [Problem] Given an integer n and m pairs of integers (ai, bi) (1 ≤ ai, bi ≤ n), find the minimum number of edges in a directed graph that satisfies the following condition:

  • For each i, there exists a path from vertex ai to vertex bi.

    对于一个n个点的强连通图最少需要n条边,而非强连通的n个有边连接的点最少需要n-1条边。那么只要判断连通起来的k个点组成的块是不是有环,如果有环需要k条边,无环需要k-1条边。在连完一个连通的块后将其合并看成一个点。直到所有点都遍历过。

#include
using namespace std;const int INF = 120009;struct Edge { int v, next;} edge[INF];int head[INF], ncnt ;int f[INF], vis[INF], cycle[INF], siz[INF];int n, m, ans;inline void adde (int u, int v) { edge[++ncnt].v = v, edge[ncnt].next = head[u]; head[u] = ncnt;}inline int find (int x) { if (f[x] == x) return x; return f[x] = find (f[x]);}inline void uin (int x, int y){ siz[find (x)] += siz[find (y)]; f[find (y)] = find (x);}inline bool dfs (int u) { vis[u] = 1; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (!vis[v]) dfs (v); if (vis[v] == 1) cycle[find (u)] = 1; } vis[u] = 2;}int main() { scanf ("%d %d", &n, &m); for (int i = 1; i <= n; i++) f[i] = i, siz[i] = 1; for (int i = 1, x, y; i <= m; i++) { scanf ("%d %d", &x, &y); adde (x, y); if (find (x) != find (y) ) uin (x, y); } for (int i = 1; i <= n; i++) if (!vis[i]) dfs (i); for (int i = 1; i <= n; i++) { if (find (i) == i) ans += siz[i] - 1; ans += cycle[i]; } printf ("%d\n", ans);}
View Code

 

D.

  题意:一个n个点m条边的无向图中所有的边都有一个颜色,有q个询问,对每个询问(u,v)输出从u到v的纯色路径条数。(n,m,q<1e5)

 

  首先应该先把所有相同颜色边连接的块做一次并查集,然后对所有询问(a,b)对a,b中有着较少的度的点的颜色查找b是否与a在一个集合。

  unordered_map能够在让查找b的时间降到O(1)

 

#include
using namespace std;const int INF = 100009;unordered_map
f[INF], old[INF];int n, m, q;inline int find (int x, int c) { if (f[x][c] < 0) return x; return f[x][c] = find (f[x][c], c);}inline void merge (int x, int y, int c) { if (f[x].find (c) == f[x].end() ) f[x][c] = -1; if (f[y].find (c) == f[y].end() ) f[y][c] = -1; x = find (x, c), y = find (y, c); if (x == y) return; f[y][c] += f[x][c]; f[x][c] = y;}int main() { scanf ("%d %d", &n, &m); for (int i = 1, x, y, c; i <= m; i++) { scanf ("%d %d %d", &x, &y, &c); merge (x, y, c); } scanf ("%d", &q); int a, b; while (q--) { scanf ("%d %d", &a, &b); if (f[a].size() > f[b].size() ) swap (a, b); if (old[a].find (b) == old[a].end() ) { int ans = 0; for (auto &c : f[a]) if (f[b].find (c.first) != f[b].end() && find (a, c.first) == find (b, c.first) ) ans++; old[a][b] = ans; } printf ("%d\n", old[a][b]); }}
View Code

 

转载于:https://www.cnblogs.com/keam37/p/4237581.html

你可能感兴趣的文章
Js 向json对象中添加新元素
查看>>
ip反查域名
查看>>
【OpenCV归纳】1 体验OpenCV
查看>>
毛毛雨的博客乐园—内容简介
查看>>
实现一个3D图片轮播插件 —— 更新版
查看>>
C# 如何实现WinForm程序自重启(重新启动自己)
查看>>
Jenkins 集成 git .net 和nuget
查看>>
(二)重定向以及传值
查看>>
Spark任务调度初识
查看>>
《Linux内核设计与实现》读书笔记(十二)- 内存管理
查看>>
Linux 小知识翻译 - 「分区」
查看>>
Linux 小知识翻译 - 「cron」
查看>>
[Sass]局部变量和全局变量
查看>>
docker 一些简略环境搭建及部分链接
查看>>
android studio获取SHA1
查看>>
怎么才能在windows使用git命令
查看>>
Sigar应用
查看>>
从单体架构到微服务的演变之路
查看>>
Valgrind内存泄露检测工具使用初步
查看>>
PDF 补丁丁 0.5.0.2657 发布
查看>>