zoukankan      html  css  js  c++  java
  • CodeForces

    题意:一张有向图,每条边上都有wi个蘑菇,第i次经过这条边能够采到w-(i-1)*i/2个蘑菇,直到它为0。问最多能在这张图上采多少个蘑菇。

    分析:在一个强连通分量内,边可以无限次地走直到该连通块内蘑菇被采完为止,因此每个强连通分量内的结果是确定的。

    设一条边权值为w,最大走过次数为t,解一元二次方程得 t = (int)(1+sqrt(1+8w));则该边对所在连通块的贡献为w*t - (t-1)*t*(t+1)/6。

    而不在任何一个强连通分量内的边,最多只能走一次。所以在缩点后的DAG上进行dp即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn =1e6+5;
    struct Edge{
        int v,next;
        LL val;  
    }edges[maxn],E[maxn];
    int head[maxn],tot,H[maxn],tt;
    stack<int> S;
    int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt;
    LL W[maxn];
    LL dp[maxn];
    void init()
    {
        tot = dfn = scc_cnt=tt=0;
        memset(H,-1,sizeof(H));
        memset(W,0,sizeof(W));
        memset(dp,0,sizeof(dp));
        memset(pre,0,sizeof(pre));
        memset(sccno,0,sizeof(sccno));
        memset(head,-1,sizeof(head));
    }
    
    void AddEdge(int u,int v,LL val)   {
        edges[tot] = (Edge){v,head[u],val};
        head[u] = tot++;
    }
    
    void Tarjan(int u)
    {
        int v;
        pre[u]=low[u]=++dfn;
        S.push(u);
        for(int i=head[u];~i;i=edges[i].next){
            v= edges[i].v;
            if(!pre[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!sccno[v]){
                low[u]=min(low[u],pre[v]);
            }
        }
        if(pre[u]==low[u]){
            int x;
            ++scc_cnt;
            for(;;){
                x = S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }    
    }
    
    
    void nAddEdge(int u,int v,LL w)
    {
        E[tt] = (Edge){v,H[u],w};
        H[u] = tt++;
    }
    
    LL dfs(int u)
    {
        if(dp[u]) return dp[u];
        for(int i=H[u];~i;i=E[i].next){
            int v = E[i].v;
            dp[u] = max(dp[u],dfs(v)+E[i].val);
        }
        dp[u]+=W[u];
        return dp[u];
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int N,M; 
        while(scanf("%d%d",&N,&M)==2){
            init();
            int st,u,v; LL w;
            while(M--){
                scanf("%d%d%lld",&u,&v,&w);
                AddEdge(u,v,w);
            }
            scanf("%d",&st);
            for(int i=1;i<=N;++i){
                if(!pre[i]){
                    Tarjan(i);
                }
            }
            
            for(int u =1;u<=N;++u){
                for(int i =head[u];~i;i = edges[i].next){
                    v = edges[i].v;
                    LL w = edges[i].val;
                    if(sccno[u]!=sccno[v]){
                        nAddEdge(sccno[u],sccno[v],w);
                    }
                    else{
                        int t = (int)(1+sqrt(1+8*w))/2;
                        W[sccno[u]] += (LL)t*w - (LL)(t-1)*t*(t+1)/6;
                    }
                }
            }
            for(int i=1;i<=scc_cnt;++i){
                if(!dp[i]){
                    dfs(i);
                }
            }
            printf("%lld
    ",dp[sccno[st]]);
        }
        return 0;
    }
    为了更好的明天
  • 相关阅读:
    Android -- 在一个Activity开启另一个Activity 并 获取他的返回值。
    Android -- Activity的生命周期,Activity四种启动模式 Standard, SingleTop,SingleTask,SingleInstance
    Python3 如何优雅地使用正则表达式(详解七)
    Python3 如何优雅地使用正则表达式(详解六)
    Python3 如何优雅地使用正则表达式(详解五)
    Python3 如何优雅地使用正则表达式(详解四)
    Python3 如何优雅地使用正则表达式(详解三)
    Python3 如何优雅地使用正则表达式(详解一)
    Windows编程中的若干难点
    魔法方法:算术运算
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9494938.html
Copyright © 2011-2022 走看看