codeforces 894 E(scc + dp)

题目链接

E. Ralph and Mushrooms

分析

很显然如果在同一个连通分量内,它可以重复踩直到踩完.而重复踩,能踩到的蘑菇数可以预处理,然后二分求得.

那么我们将它求强连通再缩点后,问题就简单了,求出每个scc的权值作为节点权值,然后dp就行.

感觉本人代码有点搓,估计是很久没写过 scc缩点了,等会儿去看看大佬的姿势再更

AC code


#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int maxn = 1e6 +10;
const int maxv = 1e8+10;
const int MOD = 1e9+7;

LL tmp[maxn],sum[maxn],t=0;
inline LL weight(LL x){
    int p = lower_bound(tmp,tmp+t,x) - tmp-1;
    return x*(p+1) - sum[p];
}
int n,m,s;
LL ans =0;
bool vis[maxn];
LL node[maxn],dp[maxn];//缩点后贡献
//scc
std::vector<int> sc_node[maxn];
std::vector<Pair> G[maxn];
int dfn[maxn],low[maxn];
int dfs_clock=0;
int scc[maxn],scc_cnt=0;
stack<int> S;//辅助栈
void dfs(int u) {
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    for(auto e:G[u]){
         int v = e.fi;
        if(!dfn[v]){
            //未访问
            dfs(v);
            low[u] = min(low[v],low[u]);
        }else if(!scc[v])low[u] = min(low[v],low[u]);
    }
    //计算出low值之后看是否满足起始条件
    if(low[u] == dfn[u]){
        //标记
        scc_cnt++;
        while (true) {
            int v = S.top();S.pop();
            scc[v] = scc_cnt;
            if(v == u)break;
        }
    }
}

LL solve(int u) {
    if(dp[u]!=-1)return dp[u];
    dp[u] = node[u];
    LL ans = 0;
    for(auto v : sc_node[u]){
        for(auto e : G[v])
            if(scc[e.fi] != u){
                ans = max(ans,solve(scc[e.fi])+e.se);
            }
    }
    return dp[u]+=ans;
}

int main(int argc, char const *argv[]) {
     for(t=0; tmp[t-1]<maxv ; ++t)tmp[t] = t+ tmp[t-1],sum[t]=tmp[t]+sum[t-1];
     cin>>n>>m;
     for(int i=0 ; i<m ; ++i){
         int x,y,w;
         scanf("%d%d%d",&x,&y,&w );
         G[x].pb(mp(y,w));
     }
     cin>>s;
     for(int i=1 ; i<=n ; ++i)
        if(!dfn[i])dfs(i);
     for(int i=1 ; i<=n ; ++i){
         sc_node[scc[i]].pb(i);
         for(auto e: G[i]){
             if(scc[e.fi]==scc[i])node[scc[i]]+=weight(e.se);
         }
     }
     ms(dp,-1);
     std::cout << solve(scc[s]) << '\n';
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值