题目链接: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;
原文地址:https://www.cnblogs.com/Xx-queue/p/11708539.html