题目: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的更多相关文章

  1. 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, ...

  2. 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 ...

  3. Codeforces Round #603 (Div. 2)F. Economic Difficulties

    F. Economic Difficulties 题目链接: https://codeforces.com/contest/1263/problem/F 题目大意: 两棵树,都有n个叶子节点,一棵树正 ...

  4. Codeforces Round #603 F Economic Difficulties

    题目大意 给你两棵树,结点分别是1-A与1-B,然后给了N台设备,并且A树和B树的叶子结点(两棵树的叶子节点数量相同)都是链接电机的.问,最多可以删掉几条边使得每个设备都能连到任意一棵(或两棵)树的根 ...

  5. codeforces div2_603 F. Economic Difficulties(树dfs预处理+dp)

    题目连接:http://codeforces.com/contest/1263/problem/F 题意:有n个设备,上和下分别连接着一颗树,上下两棵树每棵树的叶子节点连接一个设备,两棵树的根节点都是 ...

  6. CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理

    LINK:Phoenix and Memory 这场比赛标题好评 都是以凤凰这个单词开头的 有凤来仪吧. 其实和Hall定理关系不大. 不过这个定理有的时候会由于 先简述一下. 对于一张二分图 左边集 ...

  7. CF#603 Div2

    差不多半年没打cf,还是一样的菜:不过也没什么,当时是激情,现在已是兴趣了,开心就好. A Sweet Problem 思维,公式推一下过了 B PIN Codes 队友字符串取余过了,结果今天早上一 ...

  8. Codeforces #451 Div2 F

    #451 Div2 F 题意 给出一个由数字组成的字符串,要求添加一个加号和等号,满足数字无前导 0 且等式成立. 分析 对于这种只有数字的字符串,可以快速计算某一区间的字符串变成数字后并取模的值,首 ...

  9. Codeforces #452 Div2 F

    #452 Div2 F 题意 给出一个字符串, m 次操作,每次删除区间 \([l,r]\) 之间的字符 \(c\) ,输出最后得到的字符串. 分析 通过树状数组和二分,我们可以把给定的区间对应到在起 ...

随机推荐

  1. centos 7 中如何提取IP地址

    ifconfig |grep -Eo "(([1-9)?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|1[0-9]{2}|2[0-4][0 ...

  2. mybatis一级缓存和二级缓存的使用

    在mybatis中,有一级缓存和二级缓存的概念: 一级缓存:一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQLSession, Mabits默认开启一级缓存.在同一个 ...

  3. exists、in和join比较

    这个根据实际情况具体分析 遇到问题了再具体分析就行.

  4. java基础笔记(4)

    二进制运算: &的应用:清零.得到指定位的数: |的应用:将指定位置取1: ^的应用:取反.保留原值:交换两个bian变量:A= A^B,B =A ^ B,A = A^B;(原理就是本身异或本 ...

  5. Python生成文本格式的excel\xlwt生成文本格式的excel\Python设置excel单元格格式为文本\Python excel xlwt 文本格式

    Python生成文本格式的excel\xlwt生成文本格式的excel\Python设置excel单元格格式为文本\Python excel xlwt 文本格式 解决: xlwt 中设置单元格样式主要 ...

  6. 剑指offer-链表中环的入口结点-链表-python ***

    题目描述 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. 思路 第一步,用两个快慢指针找环中相汇点.分别用slow, fast指向链表头部,slow每次走一步,fast每次 ...

  7. c# 数据库基础(将连接字符串写到配置文件中)

    数据库 操作步骤 一,添加一个配置文件 内容 <?xml version="1.0" encoding="utf-8" ?> <configu ...

  8. listen - listen for connections on a socket 在一个套接字上倾听连接

    SYNOPSIS 概述 #include <sys/socket.h> int listen(int s, int backlog); DESCRIPTION 描述 在接收连接之前,首先要 ...

  9. Java web项目搭建系列之一 Eclipse中新建Maven项目

    前提条件: 已经安装好JDK 已经安装好Maven 已经安装好Eclipse 已经安装好Maven插件 在Eclipse中新建Maven项目 [File]→[New]→[Other...] [Mave ...

  10. At grand 022 GCD序列构造 dp/floyd二进制变换最少费用

    A diverse words指的是每一个字母在单词中出现的次数不超过1的单词 题目要求你求出字典序比当前给定单词大的字典序最小单词 1.如果给定的单词长度小于26 就遍历一次在单词尾部加上字典序最小 ...