码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-10-20 19:48:00      阅读:24      评论:0      收藏:0      [点我收藏+]

标签:ace   ble   tps   pre   vector   math   define   set   ==   

题目链接: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\n",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\n",dfs(color[s]));
    return 0;

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

标签:ace   ble   tps   pre   vector   math   define   set   ==   

原文地址:https://www.cnblogs.com/Xx-queue/p/11708539.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!