[Luogu2656]采蘑菇

题目大意:
  给你一个有向图,每条边有一个边权w以及恢复系数k,
  你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整。
  问你最大能获得的收益为多少?

思路:
  缩点+DP。
  首先跑一下Tarjan(只要从s开始跑,因为没跑到的地方肯定和答案没关系)。
  对于每个强连通分量,我们算一下经过这个强联通分量能获得的总收益sum(就是拼命在这上面绕圈圈)。
  把原图缩为一个DAG,然后就可以DP了。
  设当前点为i,后继结点为j,边权为w,j的SCC的总收益为sum[j],转移方程为f[j]=max{f[i]+w+sum[j]}。
  当然也只要从s开始DP即可。

  1 #include<cmath>
  2 #include<stack>
  3 #include<queue>
  4 #include<cstdio>
  5 #include<cctype>
  6 #include<vector>
  7 #include<cstring>
  8 inline int getint() {
  9     register char ch;
 10     while(!isdigit(ch=getchar()));
 11     register int x=ch^‘0‘;
 12     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘);
 13     return x;
 14 }
 15 const int N=80001,M=200000;
 16 struct Edge {
 17     int from,to,w;
 18     double k;
 19     int next;
 20 };
 21 Edge e[M];
 22 int head[N];
 23 inline void add_edge(const int &u,const int &v,const int &w,const double &k,const int &i) {
 24     e[i]=(Edge){u,v,w,k,head[u]};
 25     head[u]=i;
 26 }
 27 int s;
 28 int dfn[N],low[N],scc[N],cnt,id,sum[N],in[N];
 29 bool ins[N];
 30 std::stack<int> stack;
 31 void tarjan(const int &x) {
 32     dfn[x]=low[x]=++cnt;
 33     stack.push(x);
 34     ins[x]=true;
 35     for(int i=head[x];~i;i=e[i].next) {
 36         const int &y=e[i].to;
 37         if(!dfn[y]) {
 38             tarjan(y);
 39             low[x]=std::min(low[x],low[y]);
 40         } else if(ins[y]) {
 41             low[x]=std::min(low[x],dfn[y]);
 42         }
 43     }
 44     if(dfn[x]==low[x]) {
 45         id++;
 46         int y=0;
 47         while(y!=x) {
 48             y=stack.top();
 49             stack.pop();
 50             ins[y]=false;
 51             scc[y]=id;
 52         }
 53     }
 54 }
 55 int ans,f[N];
 56 std::queue<int> q;
 57 inline void dp() {
 58     q.push(scc[s]);
 59     f[scc[s]]=sum[scc[s]];
 60     while(!q.empty()) {
 61         const int x=q.front();
 62         q.pop();
 63         ans=std::max(ans,f[x]);
 64         for(register int i=head[x];~i;i=e[i].next) {
 65             const int &y=e[i].to;
 66             f[y]=std::max(f[y],f[x]+e[i].w+sum[y]);
 67             if(!--in[y]) q.push(y);
 68         }
 69     }
 70 }
 71 int main() {
 72     const int n=getint(),m=getint();
 73     memset(head,-1,sizeof head);
 74     for(register int i=0;i<m;i++) {
 75         const int u=getint(),v=getint(),w=getint();
 76         double k;
 77         scanf("%lf",&k);
 78         add_edge(u,v,w,k,i);
 79     }
 80     s=getint();
 81     tarjan(s);
 82     memset(head,-1,sizeof head);
 83     for(register int i=0;i<m;i++) {
 84         const int &u=e[i].from,&v=e[i].to;
 85         if(!dfn[u]||!dfn[v]) continue;
 86         if(scc[u]==scc[v]) {
 87             const double &k=e[i].k;
 88             int w=e[i].w;
 89             while(w>0) {
 90                 sum[scc[u]]+=w;
 91                 w=floor(w*k);
 92             }
 93         } else {
 94             in[scc[v]]++;
 95             add_edge(scc[u],scc[v],e[i].w,e[i].k,i);
 96         }
 97     }
 98     dp();
 99     printf("%d\n",ans);
100     return 0;
101 }
时间: 2024-10-24 00:14:03

[Luogu2656]采蘑菇的相关文章

洛谷2656 采蘑菇

本题地址:http://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇.      ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇.由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整.      比如,一条路上有4个蘑菇,这条路

[Luogu 2656] 采蘑菇

Description 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇.由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的"恢复系数",再下取整. 比如,一条路上有4个蘑菇,这条路的"恢复系数"为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为

【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇

歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1],col[2]...col[n]col[1],col[2]...col[n]由于她很挑剔,所以她只会采那些"魔法蘑菇" 一个蘑菇被叫做"魔法蘑菇",当且仅当它在给定的某段区间内,并且在这段给定区间内与它颜色相同的蘑菇(包括它本身)的个数 与在这个给定区间外这种颜色的蘑菇的

采蘑菇

洛咕 题意:ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇.由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的"恢复系数",向下取整.比如,一条路上有4个蘑菇,这条路的"恢复系数"为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.现在,小胖和ZYR从S号小树丛出发,求

Luogu P2656 采蘑菇

尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘光蘑菇能拿到的边权之和.然后,在新点之间保留原来的桥及其初始权值.(每一个桥一定只能跑一遍,否则说明这两个本应单向通行的分量之间有返回的路径,则二者可构成一个更大的分量.这个结论正是tarjan算法求有向图dcc的核心原理.)现在得到了一张新图,问题在于如何在一张包含点权.边权的DAG上求起始于定点

4.3 省选模拟赛 采蘑菇 点分治

给出一棵树 每个点都有一个颜色ci 问 从i号点出发到任意一个点的路径上本质不同的颜色之和. \(n\leq 300000\) 光线性扫描时不行的 显然有\(n^2\)的暴力. 考虑树是一条链的时候怎么做? 可以发现先求出1的答案然后维护换根的过程 记录每个点颜色的pre 前驱 nex后继很容易通过分类讨论得到答案. 考虑树的时候怎么做?还是维护换根的过程 当两个点颜色相同的时候 答案显然一样,当不同的时候 可以分析得出 要查自己子树内没有自己父亲颜色的祖先的节点个数.还要查 自己子树之外没有自

模仿东京首页banner轮播,京东新闻上下滚动动画实现(动画实现)

接着上篇 微信小程序-阅读小程序demo写:http://www.cnblogs.com/muyixiaoguang/p/5917986.html 首页banner动画实现 京东新闻上下动画实现 想着模仿京东首页呢,结果也没赶得及写完,轮播图让我搞了好长时间.也好,那就国庆8天好好的写一下,这里写了一半,先放着.先介绍一下这一半的内容.       还是老规矩,先放个图吧,虽然才一点点了 上线的banner大图和京东头条都是可以滚动的,抄写微信小程序社区官方qq群:390289365里 Nige

养养鱼,种种花,做做菜,生活是很好玩儿的

一直以为汪曾祺最近几年才去世,上网查了一下,才知道这个老头儿97年就已经不在了. 最早读到他的小说是<受戒>,被无忧无虑的江南生活所吸引,觉得很美.其实是先生所构想的世界很美,现实中不存在这样的世界,也许以前存在过,后来又消失了.之后在一本很厚的散文集中读到<跑警报>,写得很有意思,来来回回度过很多遍.这本<百年百篇经典散文>封面画了两颗很大的松果,屡次搬家中无故遗失,我专门到旧书网上淘了一本回来,成为我的常读书之一. <跑警报>写昆明西南联大的生活,最要紧

100个精彩的开源游戏

街机游戏 1.Andy's Super Great Park 骑在过山车上,躲避障碍的同时收集气球.游戏有25关,另外还有18关需要得到高分才能解锁.支持的操作系统:Windows,Linux,Android. 2.Armagetron Advanced 这是Tron的3D克隆版.在游戏中,你需要控制你的光圈来使你的竞争对手比你早撞上墙.支持单人游戏和最多16人联网游戏.支持的操作系统Windows, Linux, OS X, Android. 3.BZFlag 全称是"Battle Zone