• CF1137 C. Museums Tour


    CF1137 C. Museums Tour

    一般来说的正常思路:看到有向图的第一思路都是缩点(但是要分析一波证明强联通分量中的个体可以拼凑成整体,一般都是边和点可以经过无数次然后贡献只算一次这种类型)(DAG)上面DP.

    这道题第一眼看上去比较麻烦,因为这个时间限制比较恶心的样子.

    我们考虑拆点,将一个点拆成(d)个,((i,j))表示第(i)个点在第(j)天的联通情况

    这样的话,我们在缩点的时候,就统计一下每一个强联通分量内有多少点在其对应的博物馆的开放时间内(注意去重)

    这样的话,我们貌似就得到了每个强联通分量的点权

    剩下的貌似就是一个(DAG)上的最长链问题了.

    但是我们好像没有考虑一个点在两个或多个强联通分量都有贡献的情况

    很幸运这是不需要考虑的.因为不可能出现上述情况

    为什么?

    我们说假设存在这样一次路径,满足((i,x) ->(i,y))即从(i)点的第(x)天能够到达第(i)个点的第(y)天,我们设(Delta d = y - x)(默认(y)大于(x))

    那么一定存在((i,0)->(i,d - 1))

    以此类催,我们发现从(y)也可以到达(x),那么他们必在同一强联通分量内

    然后就结束了

    我栈用了存边数组的变量(tot)导致疯狂RE

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 3;
    const int M = 61;
    struct edge{
        int to;
        int nxt;	
    }e[N * M];
    vector <int> G[N * M];
    int val[N * M],head[N * M];
    char s[N][M];
    int tot;
    int cnt,n,m,d,idx,top;
    bool insta[N * M];
    int sta[N * M];
    int dfn[N * M],belong[N * M],low[N * M];
    int f[N * M];
    //int can[N];
    bool flag[N * M];
    int out[N * M];
    //inline char nc(){
    //    #define SIZE 100000
    //    static char buf[SIZE],*p1 = buf+SIZE,*pend = buf+SIZE;
    //    if(p1 == pend){
    //        p1 = buf;pend = buf+fread(buf,1,SIZE,stdin);
    //        if(p1 == pend) return -1;
    //    }
    //    return *p1++;
    //    #undef SIZE
    //}
    inline void read(int &x){
        x = 0;int flag = 0;
        char ch = getchar();
        while(!isdigit(ch)){
            if(ch == '-') flag = 1;
            ch = getchar();
        }
        while(isdigit(ch)){
            x = (x<<1) + (x<<3) + (ch^'0');
            ch = getchar();
        }
        if(flag) x = -x;
    }
    inline void add(int x,int y){
        e[++tot].to = y;
        e[tot].nxt = head[x];
        head[x] = tot;	
    }
    inline void tarjan(int x){
    //	cout << x  << endl;
        dfn[x] = low[x] = ++idx;
        sta[++top] = x;	
        insta[x] = 1;
        for(int i = head[x];i;i = e[i].nxt){
            int y = e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x] = min(low[x],low[y]);
            }
            else if(insta[y]) low[x] = min(low[x],dfn[y]);
        }
        if(dfn[x] == low[x]){
            int k;cnt++;
            int fo = top;
            do{
                //tot = -1;
                k = sta[top--];
                insta[k] = 0;
                belong[k] = cnt;
                if(s[k / d][k % d] == '1' && flag[k / d] == 0) {val[cnt]++;flag[k / d] = 1;}
            //	if(k % d == 0) can[cnt] = 1;
            }while(k != x);
            for(int i = fo;i != top;--i) flag[sta[i] / d] = 0;
        }
    }
    inline int tops(){
        queue <int> q;
    //	q.push(belong[0]);
    //	cout <<in[belong[0]] << endl;
        for(int i = 1;i <= cnt;++i) f[i] = val[i];
        for(int i = 1;i <= cnt;++i) if(!out[i]) f[i] = val[i],q.push(i);
        while(!q.empty()){
            int k = q.front();q.pop();
            for(int i = 0;i < (int)G[k].size();++i){
                int y = G[k][i];
                f[y] = max(f[y],f[k] + val[y]);
                out[y]--;
                if(!out[y]) q.push(y);
            }
        }
    //	for(int i = 1;i <= cnt;++i) cout << f[i] << ' ';cout << endl; 
        return f[belong[0]];
    }
    int main(){
    //	printf("%d
    ",sizeof(e) / 1024 / 1024);
        read(n),read(m),read(d);
        for(int i = 1;i <= m;++i){
            int x,y,z;
            read(x);read(y);x--,y--;
            for(int j = 0;j < d;++j)
            add(x * d + j,y * d + ((j + 1) % d));
        }
        for(int i = 0;i < n;++i) scanf("%s",s[i]);
        if(n == 1 && m == 0){
            cout << s[0][0];
            return 0;
        }
    //	if(n == 99998){cout << "GG";return 0;}
        for(int i = 0;i < n * d;++i)
        if(!dfn[i]) tarjan(i);
    //for(int i = 0;i < n * d;++i) printf("%d ",belong[i]);puts("");
    //		cout << cnt << endl;	
    //	for(int i = 1;i <= cnt;++i) cout << val[i] << " ";cout << endl; 
        for(int i = 0;i < n * d;++i){
            for(int j = head[i];j;j = e[j].nxt){
                int y = e[j].to;
                if(belong[i] != belong[y]) G[belong[y]].push_back(belong[i]),out[belong[i]]++;//printf("%d %d
    ",belong[i],belong[y]);
            }
        }
        //cout << cnt << endl;
    //	for(int i = 1;i <= cnt;++i){
    //		printf("now:%d: ",i);
    //		for(int j = 0;j < G[i].size();++j){
    //			printf("%d ",G[i][j]);	
    //		}
    //		puts("");
    //	}
        printf("%d
    ",tops());
        return 0;	
    }
    
  • 相关阅读:
    footer在最低显示
    jQuery toast message 地址 使用
    linux 获取经过N层Nginx转发的访问来源真实IP
    Java Json格式的字符串转变对象
    多个机器获取微信access-token导致的有效性问题
    站点技术---301重定向
    C++技术问题总结-第8篇 STL内存池是怎么实现的
    IIS中遇到无法预览的问题(HTTP 错误 401.3
    梯度下降深入浅出
    COM-IE-(2)
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/10966766.html
Copyright © 2020-2023  润新知