嘘~ 正在从服务器偷取页面 . . .

洛谷P2656 采蘑菇 题解


洛谷P2656 采蘑菇 题解

题目链接:P2656 采蘑菇

题意

q779 和 cxy 要去森林采蘑菇。

森林间有 \(N\) 个小树丛,\(M\) 条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。q779 和 cxy 经过某条小径一次,可以采走这条路上所有的蘑菇。由于森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数” \(c\) ,再下取整。

比如,一条路上有 \(4\) 个蘑菇,这条路的“恢复系数”为 \(c = 0.7\),则第一~四次经过这条路径所能采到的蘑菇数量分别为 \(4,2,1,0\)

现在,q779 和 cxy 从 \(S\) 号小树丛出发,求他们最多能采到多少蘑菇。

输入格式

第一行两个整数,\(N\)\(M\)

第二行到第 \(M+1\) 行,每行四个数,分别表示一条小路的起点、终点、初始蘑菇数和恢复系数。

\(M+2\) 行,一个整数 \(S\)

输出格式

一行一个整数,表示最多能采到多少蘑菇,保证答案不超过 \(2^{31}-1\)

数据范围

\(1 \le N\le 8\times 10^4,~1\le M\le 2\times 10^5,~0\le c\le 0.8\) 且最多有一位小数, \(1\le S\le N\)

复活后的第一篇题解,也是一道热身题。无论如何,愿我圆梦NOIP。

注意到一条边可以走无数遍,那么任何强连通分量都可以走到不长蘑菇为止。

考虑缩点并预处理每个强连通分量的答案,然后就变成简单的 DAG 上跑 topo+dp 了

时间复杂度 \(\mathcal{O}(m \log_{\frac{4}{5}} M)\) ,总之能过

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(8e4 + 15))
#define M ((int)(2e5 + 15))

int n,m,s,pos=1,scnt,stktop,head[N],f[N],g[N];
int dfn[N],low[N],stk[N],scc[N],val[N]; bitset<N> ins;
struct Edge { int u,v,w,c,next; } e[M];
void addEdge(int u,int v,int w,double c)
{ e[++pos] = {u,v,w,(int)(c * 10),head[u]}; head[u] = pos; }
void Tarjan(int u)
{
    static int tim = 0;
    dfn[u] = low[u] = ++tim; ins[u] = 1; stk[++stktop] = u;
    for(int i=head[u]; i; i=e[i].next)
    {
        int v = e[i].v; if(!dfn[v])
        {
            Tarjan(v); down(low[u], low[v]);
        }else if(ins[v]) down(low[u], dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ++scnt;
        for(int p = 0; p != u; )
        { p = stk[stktop--]; ins[p] = 0; scc[p] = scnt; }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    for(int i=1,u,v,w; i<=m; i++)
    {
        static double c;
        cin >> u >> v >> w >> c; addEdge(u,v,w,c);
    }
    cin >> s; Tarjan(s);
    pos = 1; for(int i=1; i<=n; i++) head[i] = 0;
    for(int i=2; i <= m+1; i++)
    {
        int u = scc[e[i].u], v = scc[e[i].v];
        if(!(u && v)) continue;
        if(u != v) addEdge(u,v,e[i].w,-1);
        else while(e[i].w){ g[u] += e[i].w; e[i].w = e[i].w * e[i].c / 10; }  
    }
    // for(int i=1; i<=scnt; i++) cout << f[i] << " \n"[i==scnt];
    // for(int i=2; i<=pos; i++) cout << e[i].u << ' ' << e[i].v << ' ' << e[i].w << '\n';
    for(int u = scnt; u; u--)
    {
        if(!f[u]) f[u] = g[u];
        for(int i=head[u]; i; i=e[i].next)
        { int v = e[i].v; up(f[v], f[u] + e[i].w + g[v]); }
    }
    cout << *max_element(f + 1, f + 1 + scnt) << '\n';
    return 0;
}

黑魔法通常被认为会腐蚀那些使用者,这也是它们被称为黑魔法的部分原因。


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录