• [CF1137]Museums Tour


    ( ext{Description:})

    一个国家有 (n) 个城市,(m) 条有向道路组成。在这个国家一个星期有 (d) 天,每个城市有一个博物馆。

    有个旅行团在城市 (1) 出发,当天是星期一。每天早上,如果这个城市的博物馆开了,那么可以去这个博物馆参观。每天晚上,旅行团可以选择沿一条出边前往下一个城市,或者结束旅行。一个城市可以经过多次。

    请问旅行团最多能参观多少个博物馆。一个博物馆参观了多次,只计算一次。

    (1le n, mle 10^5,1le dle 50)

    ({ m Solution:})

    由于({ m d})只有({ m 50})天,所以考虑分层图,分成({ m 50})层,每个点只有在它开放的那个时间(那一层)有({ m 1})的权值,其余权值均为({ m 0}),对于原图的一条边 ({ m E(x, y)}), 在分层图中 ({ m E(x_i, y_{i+1}), (1le ile d-1)})({ m E(x_d, y_1)})

    然后缩点成({ m DAG}), ({ m DP}) 即可。

    注意一个细节就是如果很多个点 ({ m x_i}) 在同一个强连通分量中,权值只加一次。

    #include <vector>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <assert.h>
    #include <algorithm>
    
    using namespace std;
    
    #define LL long long
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define GO debug("GO
    ")
    #define rep(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i))
    
    const int INF = 0x3f3f3f3f;
    const char Enter = '
    ';
    inline int rint() {
      register int x = 0, f = 1; register char c;
      while (!isdigit(c = getchar())) if (c == '-') f = -1;
      while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
      return x * f;
    }
    struct Stream {
        Stream operator>> (int &x)
        { x = rint(); return *this; }
        Stream operator<< (int x)
        { printf("%d", x); return *this; }
        Stream operator<< (char ch)
        { putchar(ch); return *this; }
    } xin, xout;
    
    template<typename T> inline void chkmin(T &a, T b) { a > b ? a = b : 0; }
    template<typename T> inline void chkmax(T &a, T b) { a < b ? a = b : 0; }
    
    const int N = 1e5 + 10;
    
    struct Edge {
        int v, nxt;
    } E[N * 51];
    int tot, head[N * 51];
    vector<int> G[N * 51];
    
    inline void add(int u, int v) 
    { E[++tot] = (Edge){v, head[u]}; head[u] = tot; }
    
    int n, m, d, val[N * 50], col[N * 50], dfn[N * 50], low[N * 50], have[N * 50];
    
    stack<int> stk;
    void tarjan(int u) {
        dfn[u] = low[u] = ++dfn[0];
        stk.push(u);
        for (register int i = head[u]; i; i = E[i].nxt) {
            int v = E[i].v;
            if (!dfn[v]) tarjan(v), chkmin(low[u], low[v]);
            else if (!col[v]) chkmin(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            col[0]++;
            int v;
            do {
                v = stk.top(); stk.pop();
                col[v] = col[0];
            } while (v != u);
        }
    }
    
    int dp[N * 50];
    
    int DFS(int u) {
        if (dp[u]) return dp[u];
        for (int i = 0; i < G[u].size(); ++  i) {
            int v = G[u][i];
            chkmax(dp[u], DFS(v));
        }
        return dp[u] += val[u];
    }
    
    
    int main() {
        xin >> n >> m >> d;// fast_read
        int u, v;
        rep(i, 1, m) {
            xin >> u >> v;
            rep(j, 1, d - 1) add(u + (j - 1) * n, v + j * n);
            add(u + (d - 1) * n, v);
        }
        rep(i, 1, d * n) if (!dfn[i]) tarjan(i);
    
        rep(i, 1, n * d) for (register int j = head[i]; j; j = E[j].nxt) if (col[E[j].v] != col[i]) 
                    G[col[i]].push_back(col[E[j].v]);
    
        rep(i, 1, n) {
            static char str[N]; scanf("%s", str + 1);
            rep(j, 1, d) {
                if (str[j] == '1' and have[col[i + (j - 1) * n]] != i) 
                    have[col[i + (j - 1) * n]] = i, val[col[i + (j - 1) * n]]++;
            }
        }
    
        xout << DFS(col[1]) << Enter;
    
        return 0;
    }
    
  • 相关阅读:
    SpringBoot启动流程分析(六):IoC容器依赖注入
    SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
    SpringBoot启动流程分析(四):IoC容器的初始化过程
    Razor语法大全
    VS快捷方式小技巧
    DataTable 修改列名 删除列 调整列顺序
    更改DataTable列名方法
    log4net使用详解
    C#使用Log4Net记录日志
    经典SQL语句大全
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/10637228.html
Copyright © 2020-2023  润新知