[2019CSP-S赛前训练][CF894E] Ralph and Mushrooms

Posted xx-queue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[2019CSP-S赛前训练][CF894E] Ralph and Mushrooms相关的知识,希望对你有一定的参考价值。

题目链接:https://www.luogu.org/problem/CF894E

题目大意
Ralph打算去蘑菇森林采蘑菇。

蘑菇森林里有n个蘑菇丛,有m条有向的路连接这些丛林(可能连向自己,也可能两个丛林之间有多条路)。经过某条路时,Ralph可以采走这条路上的全部蘑菇。然而,这是一片神奇的蘑菇森林,蘑菇被采走后会重新长出来一些。但是,第k次走过这条路后,这条路上重新长出的蘑菇会比上次少k。(举个栗子,第一次有w个蘑菇,第二次有w-1个蘑菇,第三次有w-1-2个蘑菇,以此类推……)(还有,蘑菇的数量大于0)。

那么,Ralph最多可以采到多少蘑菇呢?
输入输出样例
输入 #1

2 2
1 2 4
2 1 4
1

输出 #1

16

输入 #2

3 3
1 2 4
2 3 3
1 3 8
1

输出 #2

8

这个题目应该不难想到,一个强连通分量内的所有蘑菇都可以采光(重复走,一直绕圈把路上的所有蘑菇采掉)

那么一个强连通分量内的所有蘑菇数量是多少呢?

({n(n+1)<=w}) 的最大的 ({n}) ,解二次不等式,(n) 就是 (1.0*sqrt{0.25+2a}-0.5)

然后价值就是 (nw?sum^{n}_{i=1}i(i+1)/2+w) ,也就是 ({nw?n(n+1)(n+2)/6+w})

所以我们可以先用Tarjan缩点求出强连通分量,把边权合并到点上,重新建图,再来搜索一下就OK了;

那么注意几个地方:1.要开long long;

2.点权与边权混合加时不要漏加了终点的点权;

3.代码可能有点难调,耐心一点,一定可以调出来的(祭本题提交9次);

附上双倍经验:P2656 采蘑菇,稍微修改一下就能过了!

#include <bits/stdc++.h>
#define N (2000000+5)
#define int long long
using namespace std;
int n,m,s;
int top,sum,deep;
int dfn[N],low[N],color[N],vis[N],st[N];
int cnt[N],in[N],wp[N],f[N];
int u[N],v[N],wei[N];
vector <int> edge[N],w[N];
void Tarjan(int u)
{
    vis[u]=1;
    dfn[u]=low[u]=++deep;
    st[++top]=u;
    for(int i=0;i<edge[u].size();i++)
    {
        int now=edge[u][i];
        if(!dfn[now])
        {
            Tarjan(now);
            low[u]=min(low[u],low[now]);
        }
        else
        {
            if(vis[now]) low[u]=min(low[u],low[now]);
        }
    }
    if(dfn[u]==low[u])
    {
        color[u]=++sum;
        vis[u]=0;
        while(st[top]!=u)
        {
            color[st[top]]=sum;
            vis[st[top--]]=0;
        }
        top--;
    }
}
int dfs(int u)
{
    if(vis[u]) return f[u];
    int res=0;
    vis[u]=1;
    for (int i=0;i<edge[u].size();i++)
    {
        int now=edge[u][i];
        res=max(res,dfs(now)+w[u][i]);
    }
    return f[u]=res+wp[u];
}
int cont(int a)
{
    int k=1.0*sqrt(0.25+2*a)-0.5;
    return a*k-k*(k+1)*(k+2)/6+a;
}
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&u[i],&v[i],&wei[i]);
        edge[u[i]].push_back(v[i]);
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
    for(int i=1;i<=n;i++) vector<int>().swap(edge[i]);
    for(int i=1;i<=m;i++)
    {
        if(color[u[i]]==color[v[i]])
        {
            wp[color[u[i]]]+=cont(wei[i]);
        }
        else
        {
            //printf("u=%lld v=%lld
",color[u[i]],color[v[i]]);
            edge[color[u[i]]].push_back(color[v[i]]);
            w[color[u[i]]].push_back(wei[i]);
            in[color[v[i]]]++;
        }
    }
    scanf("%lld",&s);
    memset(vis,0,sizeof(vis));
    printf("%lld
",dfs(color[s]));
    return 0;

以上是关于[2019CSP-S赛前训练][CF894E] Ralph and Mushrooms的主要内容,如果未能解决你的问题,请参考以下文章

CF894E Ralph and Mushrooms

「CF894E」 Ralph and Mushrooms

day1训练(省赛前)

CSP-S 2019提高组训练 服务器需求

XJOI contest 1592

2019.9.29 csp-s模拟测试55 反思总结