牛客多校第二场B discount 基环内向树
题意:
有n种商品,每种商品有一个价格 p[i] 。
每种商品都有2种打折方式:
1. 给你优惠 d[i] 元。
2. 免费送你第 f[i] 种饮料。
现在求每种饮料至少一瓶的最小花费。
dp[i][0] 表示 i 的子树内所有的饮料都至少买了一瓶。
dp[i][1] 表示 i 的子树内所有的饮料都至少买了一瓶 且 第i种饮料是使用第2种方式购买的。
我们考虑树的转移方式。
sum[i] 表示 dp[son[i]][0] 的和
dp[i][1] = sum[i] + p[i]
dp[i][0] = min(p[i]-d[i]+sum[i], sum[i] - dp[son[i][0] + dp[son[i][1] )
然后我们可以先把环都抠出来, 然后将环上的边都标记一下,
然后先把环的子树都转移到环上来, 最后再处理环的问题。
假设一个环为 a -> b -> c -> d -> a ,mn 为这个环的最小花费。
我们断开a -> b 这条边,并且 b 不是 通过 a 送来的。
G[0][0] = dp[b][0] G[0][1] = dp[b][1]
路上转移的状态为 G[1][1] = dp[c][1] + G[0][0];
G[1][0] = min(G[0][1]+sum[c], dp[c][0] + G[0][0])
这样一直转移到G[3][0]
因为我们规定b 不是 通过 a 送来的。 mn = min(mn, G[3][0])
然后我们假设 b 是通过 a 送过来的
G[0][0] = sum[b] G[0][1] = dp[b][1]
然后通过上面的转移方程转移到G[3][1]。
因为b是a送的 那么 a 必须要按方式1购买 所以 mn = min(mn, G[3][1])
最后将 mn 加入答案中。
然后 跑完所有环之后 就能得到答案了。
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int p[N], d[N], f[N];
int head[N], to[N], nt[N];
int vis[N];
int cntCir = , tot = , top, n;
int sta[N];
vector<int> cir[N];
int vvis[N];
LL dp[N][];
LL sum[N];
LL G[N][];
void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void getCir(int u){
if(vis[u] == ) return ;
if(vis[u] == -){
cntCir++;
for(int i = top; i >= ; i--){
cir[cntCir].pb(sta[i]);
vvis[sta[i]] = ;
if(sta[i] == u) break;
}
return;
}
vis[u] = -;
sta[++top] = u;
getCir(f[u]);
top--;
vis[u] = ;
}
void dfs(int u){
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dfs(to[i]);
sum[u] += dp[to[i]][];
}
dp[u][] = sum[u] + p[u];
dp[u][] = sum[u] + p[u] - d[u];
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dp[u][] = min(dp[u][], sum[u] - dp[to[i]][] + dp[to[i]][]);
}
}
int main(){
memset(head, -, sizeof(head));
scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%d", &p[i]);
for(int i = ; i <= n; i++) scanf("%d", &d[i]);
for(int i = ; i <= n; i++) {
scanf("%d", &f[i]);
add(f[i], i);
}
for(int i = ; i <= n; i++){
if(!vis[i]){
top = ;
getCir(i);
}
}
LL ans = ;
for(int i = ; i <= cntCir; i++){
reverse(cir[i].begin(), cir[i].end());
for(int j = ; j < cir[i].size(); j++){
dfs(cir[i][j]);
}
LL mn = INF;
G[][] = dp[cir[i][]][];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
G[][] = sum[cir[i][]];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
ans += mn;
}
printf("%lld\n", ans);
return ;
}
牛客多校第二场B discount 基环内向树的更多相关文章
- 2019牛客多校第二场E MAZE(线段树 + 矩阵)题解
题意: n * m的矩阵,为0表示可以走,1不可以走.规定每走一步只能向下.向左.向右走.现给定两种操作: 一.1 x y表示翻转坐标(x,y)的0.1. 二.2 x y表示从(1,x)走到(n,y) ...
- 2019牛客多校第二场 A Eddy Walker(概率推公式)
2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...
- 牛客多校第二场A run(基础DP)
链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...
- run (牛客多校第二场)计数DP
链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 题目描述 White Cloud is exercising in the playground ...
- 2019牛客多校第二场H-Second Large Rectangle
Second Large Rectangle 题目传送门 解题思路 先求出每个点上的高,再利用单调栈分别求出每个点左右两边第一个高小于自己的位置,从而而得出最后一个大于等于自己的位置,进而求出自己的位 ...
- 2019年牛客多校第二场 H题Second Large Rectangle
题目链接 传送门 题意 求在\(n\times m\)的\(01\)子矩阵中找出面积第二大的内部全是\(1\)的子矩阵的面积大小. 思路 处理出每个位置往左连续有多少个\(1\),然后对每一列跑单调栈 ...
- [2019牛客多校第二场][G. Polygons]
题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...
- 第二大矩阵面积--(stack)牛客多校第二场-- Second Large Rectangle
题意: 给你一幅图,问你第二大矩形面积是多少. 思路: 直接一行行跑stack求最大矩阵面积的经典算法,不断更新第二大矩形面积,注意第二大矩形可能在第一大矩形里面. #define IOS ios_b ...
- 2019 牛客多校第二场 H Second Large Rectangle
题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目大意 给定一个 n * m 的 01 矩阵,求其中第二大的子矩阵,子矩阵元素必须全部为 1.输出其大小 ...
随机推荐
- Docker 容器基本操作[Docker 系列-2]
Docker 入门及安装[Docker 系列-1] 镜像就像是一个安装程序,而容器则是程序运行时的一个状态. 查看容器 查看容器 启动 docker 后,使用 docker ps 命令可以查看当前正 ...
- Python实现批量处理扫描特定目录
## 简述在渗透测试中遇到相同CMS站点时,搞定一个站点,相当于拿了一个站群的通用漏洞,所以我们首先需要标注站点的CMS类型,根据要求编写如下脚本 ## 要求1.访问特定目录,如:站点特定 /cmsa ...
- 【OpenCV-ANN神经网络自动驾驶】树莓派OpenCV神经网络自动驾驶小车【源码+实物】
没错!这个是我的毕业设计!!! 整个电子信息学院唯一一个优秀毕业设计 拿到这里炫耀了 实物如下: 电脑端显示效果: 自动驾驶实现过程: 1. 收集图像数据.建立局域网,让主机和Raspberry Pi ...
- vue前后分离项目部署(不同端口号,nginx反向代理解决跨域问题)
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #erro ...
- 03、Swagger2和Springmvc整合详细记录(爬坑记录)
时间 内容 备注 2018年6月18日 基本使用 spirngmvc整合swagger2 开始之前这个系列博文基本是,在项目的使用中一些模块的内容记录,但是后期逐渐优化,不单单是整合内容. swagg ...
- React之动画实现
React之动画实现 一,介绍与需求 1.1,介绍 1,Ant Motion Ant Motion能够快速在 React 框架中使用动画.在 React 框架下,只需要一段简单的代码就可以实现动画效果 ...
- 利用ImageAI库只需几行python代码超简实现目标检测
目录 什么是目标检测 目标检测算法 Two Stages One Stage python实现 依赖 安装 使用 附录 什么是目标检测 目标检测关注图像中特定的物体目标,需要同时解决解决定位(loca ...
- LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)
本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说 ...
- 逆向破解之160个CrackMe —— 004-005
CrackMe —— 004 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...
- linux后台运行的几种方式
1.nohup将程序以忽略挂起信号的方式运行起来 补充说明nohup命令 可以将程序以忽略挂起信号的方式运行起来,被运行的程序的输出信息将不会显示到终端.无论是否将 nohup 命令的输出重定向到终端 ...