• Codeforces Round #286 (Div. 1) 解题报告


    A.Mr. Kitayuta, the Treasure Hunter

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

    #include<bits/stdc++.h>
    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
    ", ans - 1);
    }
    View Code

    B.Mr. Kitayuta's Technology

         [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<bits/stdc++.h>
    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
    ", ans);
    }
    View Code

    D.Mr. Kitayuta's Colorful Graph

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

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

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

    #include<bits/stdc++.h>
    using namespace std;
    const int INF = 100009;
    
    unordered_map<int, int> 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
    ", old[a][b]);
        }
    }
    View Code
  • 相关阅读:
    c# volatile 关键字的拾遗补漏
    WPF中的动画控制
    【北亚数据恢复】MSSQL 2000出现“823”报错信息的数据恢复案例
    【北亚数据恢复】vmfs还原快照导致SqlServer数据库数据丢失的数据恢复案例
    【北亚数据恢复】同步数据过程中,硬盘掉线导致raid5崩溃的数据恢复
    【北亚数据恢复】HP P2000服务器 RAID5硬盘故障掉线的数据恢复
    【北亚数据恢复】Hp DL380服务器raid磁盘故障的数据库数据恢复案例
    【北亚数据恢复】NTFS文件系统误操作导致raid5中的分区被格式化时的数据恢复方法
    【北亚数据恢复】DELL EqualLogic PS6100服务器raid5硬盘出现坏道掉线的数据恢复
    【北亚数据恢复】MongoDB数据迁移文件丢失的MongoDB数据恢复案例
  • 原文地址:https://www.cnblogs.com/keam37/p/4237581.html
Copyright © 2020-2023  润新知