[CF Round603 Div2 F]Economic Difficulties
题目:Economic Difficulties
传送门:https://codeforces.com/contest/1263/problem/F
题意:给了两棵tree:Ta(拥有a个节点,节点编号为[n+1, n+a]) Tb(拥有b个节点, 节点编号: [n+ a + 1, n + a + b]) 其中两颗tree的叶子节点按照dfs序依次连续连向 $ i, i \in [1, n] $节点,询问最多可以去掉多少的tree上节点,使得每一个$i , i \in [1, n]$ 仍然可以连通Ta,或者Tb的根节点。
分析:
1.做法一:https://codeforces.com/blog/entry/71844?locale=en
类似泛化背包,每个物品要么选择a,要么选择b,连续选择有额外贡献,假设cost_a[i,j]代表[i,j]区间选择a的贡献,cost_b[i,j]代表[i,j]区间选择b的贡献。
dp[i]代表前i个节点,方程:$$ dp[i] = max\{dp[j] + cost[j+1,i] \}$$
#include <bits/stdc++.h>
using namespace std; vector< vector<int> > calc_cost(int vn, int n, vector<int> fa, vector<int> tg) {
vector< vector<int> > res(n+, vector<int>(n+));
for (int l = ; l <= n; l++) {
vector<int> deg(vn+);
for (int i = ; i <= vn ; i++) deg[fa[i]]++;
int val = ;
for (int r = l; r <= n; r++) {
for(int v = tg[r]; v != && deg[v] == ; --deg[v = fa[v]])
val++;
res[l][r] = val;
}
}
return res;
} int main() {
int n;
scanf("%d", &n);
vector< vector<int> > cost[];
for (int j = ; j < ; j++) {
int vn;
scanf("%d", &vn);
vector<int> fa(vn+);
vector<int> tg(n+);
for (int i = ; i <= vn; i++) scanf("%d", &fa[i]);
for (int i = ; i <= n; i++) scanf("%d", &tg[i]);
cost[j] = calc_cost(vn, n, fa, tg);
} vector<int> dp(n + , );
for (int i = ; i <= n; i++)
for (int j = ; j < i; j++)
dp[i] = max(dp[i], dp[j] + max(cost[][j+][i], cost[][j+][i]));
printf("%d", dp[n]);
return ;
}
2.基于最后的结果,我们肯定是选择Ta和Tb的一些节点,去除这些节点及其后代节点,考虑到这里,我们只要把每个节点控制的区间算出来,然后按照左端点或者有端点排序,然后做限制背包dp。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + ;
const int INF = 1e9 + ;
vector< pair<pair<int,int>, int> > vec;
int sz[MAXN], st[MAXN], ed[MAXN], tg[MAXN];
vector<int> G[MAXN];
void dfs(int u) {
sz[u] = ;
st[u] = INF; ed[u] = -INF;
if(tg[u]) st[u] = ed[u] = tg[u];
for(auto v : G[u]) {
dfs(v);
sz[u] += sz[v];
st[u] = min(st[u], st[v]);
ed[u] = max(ed[u], ed[v]);
}
vec.push_back(make_pair(make_pair(ed[u], st[u] - ), sz[u]-(u == )));
}
int dp[MAXN];
int main() {
int n, a, x;
scanf("%d", &n);
for(int j = ; j < ; j++) {
scanf("%d", &a);
for(int i = ;i <= a; i++) {
scanf("%d", &x);
G[x].push_back(i);
}
for(int i = ; i <= n; i++) {
scanf("%d", &x);
tg[x] = i;
}
dfs();
for(int i = ; i <= a; i++) {
G[i].clear();
tg[i] = ;
}
}
sort(vec.begin(), vec.end());
for(auto it : vec) {
int l = it.first.second, r = it.first.first;
dp[r] = max(dp[r], dp[l] + it.second);
}
printf("%d", dp[n]);
return ;
}
3.和文理分科类似,该题也可以用网络流求解,然而我到现在都不知道为啥是对的。
#include <bits/stdc++.h>
using namespace std;
typedef int LL;
const int MAXN = 1e5 + ;
const int MAXM = 1e5 + ;
const int INF = 1e9 + ; namespace NWF {
struct Edge {
int to, nxt;LL f;
} e[MAXM << ];
int S, T, tot;
int ecnt, head[MAXN], cur[MAXN], dis[MAXN];
queue<int> q;
void init(int _S, int _T, int _tot){
ecnt = ; S = _S; T = _T; tot = _tot;
memset(head, , (tot + ) * sizeof(int));
}
void addEdge(int u, int v, LL f) {
e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
e[++ecnt] = (Edge) {u, head[v], }; head[v] = ecnt;
}
bool bfs() {
memset(dis, , (tot + ) * sizeof(int));
q.push(S); dis[S] = ;
while (!q.empty()) {
int u = q.front(), v; q.pop();
for (int i = cur[u] = head[u]; i ; i = e[i].nxt) {
if (e[i].f && !dis[v = e[i].to]) {
q.push(v);
dis[v] = dis[u] + ;
}
}
}
return dis[T];
}
LL dfs(int u, LL maxf) {
if (u == T) return maxf;
LL sumf = maxf;
for (int &i = cur[u]; i; i = e[i].nxt) {
if (e[i].f && dis[e[i].to] > dis[u]) {
LL tmpf = dfs(e[i].to, min(sumf, e[i].f));
e[i].f -= tmpf; e[i ^ ].f += tmpf;
sumf -= tmpf;
if (!sumf) return maxf;
}
}
return maxf - sumf;
}
LL dinic() {
LL ret = ;
while (bfs()) ret += dfs(S, INF);
return ret;
}
}
int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
int main() {
int n, A, B;
scanf("%d", &n);
scanf("%d", &A);
for(int i = ;i <= A; i++) scanf("%d", faa+i);
for(int i = ; i <= n; i++) scanf("%d", tga + i);
scanf("%d", &B);
for(int i = ;i <= B; i++) scanf("%d", fab+i);
for(int i = ; i <= n; i++) scanf("%d", tgb + i); NWF::init(A+B+,A+B+, A+B+);
for (int i = ; i <= A; i++) {
NWF::addEdge(NWF::S, i, );
NWF::addEdge(faa[i], i, INF);
}
for (int i = ; i <= B; i++) {
NWF::addEdge(A + i, A + fab[i], INF);
NWF::addEdge(A + i, NWF::T, );
}
for (int i = ; i <= n; i++)
NWF::addEdge(tga[i], A + tgb[i], INF); int ans = A - + B - - NWF::dinic();
printf("%d", ans);
return ;
}
#include <bits/stdc++.h>
using namespace std;
typedef int LL;
const int MAXN = 1e5 + ;
const int MAXM = 1e5 + ;
const int INF = 1e9 + ; namespace NWF {
struct Edge{
int to, nxt;LL f;
}e[MAXM << ];
int S, T, tot;
int ecnt, head[MAXN], cur[MAXN], pre[MAXN], num[MAXN], dis[MAXN];
queue<int> q;
void init(int _S, int _T, int _tot){
ecnt = ; S = _S; T = _T; tot = _tot;
memset(num, , (tot + ) * sizeof(int));
memset(head, , (tot + ) * sizeof(int));
}
inline void addEdge(int u, int v, LL f) {
e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
e[++ecnt] = (Edge) {u, head[v], }; head[v] = ecnt;
}
void bfs() {
memset(dis, , (tot + ) * sizeof(int));
q.push(T);
dis[T] = ;
while(!q.empty()) {
int u = q.front(), v; q.pop();
num[dis[u]]++;
for(int i = cur[u] = head[u]; i; i = e[i].nxt) {
if(!dis[v = e[i].to]) {
dis[v] = dis[u] + ;
q.push(v);
}
}
}
}
LL augment() {
LL flow = INF;
for(int i = S; i != T; i = e[cur[i]].to)
flow = min(flow, e[cur[i]].f);
for(int i = S; i != T; i = e[cur[i]].to) {
e[cur[i]].f -= flow;
e[cur[i] ^ ].f += flow;
}
return flow;
}
LL isap() {
bfs();
int u = S, v;
LL flow = ;
while(dis[S] <= tot) {
if(u == T) {
flow += augment();
u = S;
}
bool fg = ;
for(int i = cur[u]; i; i = e[i].nxt) {
if(e[i].f && dis[u] > dis[v = e[i].to]) {
pre[v] = u;
cur[u] = i;
u = v;
fg = ;
break;
}
}
if(fg) continue;
if(!--num[dis[u]]) break;
int maxDis = tot;
for(int i = head[u]; i; i = e[i].nxt) {
if(e[i].f && maxDis > dis[v = e[i].to]) {
maxDis = dis[v];
cur[u] = i;
}
}
num[dis[u] = maxDis + ]++;
if(u != S) u = pre[u];
}
return flow;
}
}
int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
int main() {
int n, A, B;
scanf("%d", &n);
scanf("%d", &A);
for(int i = ;i <= A; i++) scanf("%d", faa+i);
for(int i = ; i <= n; i++) scanf("%d", tga + i);
scanf("%d", &B);
for(int i = ;i <= B; i++) scanf("%d", fab+i);
for(int i = ; i <= n; i++) scanf("%d", tgb + i); NWF::init(A+B+,A+B+, A+B+);
for (int i = ; i <= A; i++) {
NWF::addEdge(NWF::S, i, );
NWF::addEdge(faa[i], i, INF);
}
for (int i = ; i <= B; i++) {
NWF::addEdge(A + i, A + fab[i], INF);
NWF::addEdge(A + i, NWF::T, );
}
for (int i = ; i <= n; i++)
NWF::addEdge(tga[i], A + tgb[i], INF); int ans = A - + B - - NWF::isap();
printf("%d", ans);
return ;
}
[CF Round603 Div2 F]Economic Difficulties的更多相关文章
- cf 442 div2 F. Ann and Books(莫队算法)
cf 442 div2 F. Ann and Books(莫队算法) 题意: \(给出n和k,和a_i,sum_i表示前i个数的和,有q个查询[l,r]\) 每次查询区间\([l,r]内有多少对(i, ...
- Codeforces Round #603 (Div. 2) F. Economic Difficulties dp
F. Economic Difficulties An electrical grid in Berland palaces consists of 2 grids: main and reserve ...
- Codeforces Round #603 (Div. 2)F. Economic Difficulties
F. Economic Difficulties 题目链接: https://codeforces.com/contest/1263/problem/F 题目大意: 两棵树,都有n个叶子节点,一棵树正 ...
- Codeforces Round #603 F Economic Difficulties
题目大意 给你两棵树,结点分别是1-A与1-B,然后给了N台设备,并且A树和B树的叶子结点(两棵树的叶子节点数量相同)都是链接电机的.问,最多可以删掉几条边使得每个设备都能连到任意一棵(或两棵)树的根 ...
- codeforces div2_603 F. Economic Difficulties(树dfs预处理+dp)
题目连接:http://codeforces.com/contest/1263/problem/F 题意:有n个设备,上和下分别连接着一颗树,上下两棵树每棵树的叶子节点连接一个设备,两棵树的根节点都是 ...
- CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理
LINK:Phoenix and Memory 这场比赛标题好评 都是以凤凰这个单词开头的 有凤来仪吧. 其实和Hall定理关系不大. 不过这个定理有的时候会由于 先简述一下. 对于一张二分图 左边集 ...
- CF#603 Div2
差不多半年没打cf,还是一样的菜:不过也没什么,当时是激情,现在已是兴趣了,开心就好. A Sweet Problem 思维,公式推一下过了 B PIN Codes 队友字符串取余过了,结果今天早上一 ...
- Codeforces #451 Div2 F
#451 Div2 F 题意 给出一个由数字组成的字符串,要求添加一个加号和等号,满足数字无前导 0 且等式成立. 分析 对于这种只有数字的字符串,可以快速计算某一区间的字符串变成数字后并取模的值,首 ...
- Codeforces #452 Div2 F
#452 Div2 F 题意 给出一个字符串, m 次操作,每次删除区间 \([l,r]\) 之间的字符 \(c\) ,输出最后得到的字符串. 分析 通过树状数组和二分,我们可以把给定的区间对应到在起 ...
随机推荐
- js 中 json.stringfy()将对象、数组转换成字符串
json.stringfy()将对象.数组转换成字符串 var student = new Object(); student.name = "Lanny"; student.ag ...
- linux 文件属性文件权限
权限 -rw-------. root root Mar : anaconda-ks.cfg drwxr-xr-x root root May : dir1 drwxr-xr-x root root ...
- vue组件事件(极客时间Vue视频笔记)
vue组件核心:事件 <body> <div class="app"> <todo-list></todo-list> {{mess ...
- Linux0.11之初识Makefile/build.c
前言 Makefile对于从来没有接触过的人来说是相当别扭的(比如我),但它确实又是非常重要的,它描述了一个Image是如何形成的,理解它也许并不能帮我解决实际问题,而且编写Makefile的工作也许 ...
- dsu on tree 与长链剖分
dsu on tree 对于树进行轻重链剖分,对于节点 $x$ ,递归所有轻儿子后消除其影响,递归重儿子,不消除其影响. 然后对于所有轻儿子的子树暴力,从而得到 $x$ 的答案. 对于要消除暴力消除即 ...
- 重写select
select 模拟 目前仿写select的方式 给tableIndex 来使 div(无法获取焦点的元素)来获取元素,这样便可以在失去焦点时,是否将下拉框收回 通过 document的点击,来判断是否 ...
- 检验Excel中数据是否与数据库中数据重复
#region 记录Excel中的重复列 /// <summary> /// 记录Excel中的重复列 /// </summary> /// <param name=&q ...
- mysql复习(1)基本CRUD操作
一.这段时间在学校,把之前的东西都好好捡起来. 0.下面介绍Mysql的最基本的增删改查操作,很多IT工作者都必须掌握的命令,也是IT面试最常考的知识点.在进行增删改查之前,先建立一个包含数据表use ...
- js中的Math对象
绝对值Math.abs() console.log(Math.abs(-25)); console.log(Math.abs('-25'));//存在隐式转换可以求绝对值 co ...
- java上传文件-大文件以二进制保存到数据库
转自:https://blog.csdn.net/qq_29631069/article/details/70054201 1 一.创建表 oracle: create table baoxianda ...