题目

描述

题目大意

有一个010101序列,可以改变状态,每个状态改变都有固定的代价。

接下来有些人想要将一些位置改成特定的状态,如果按照他们要求做了就可以得到一些钱,

否则得不到,有时还要陪钱。

问最后的钱最多是多少。


思考历程

看到这题的第一眼就觉得是一道神题。

只能想到最恐怖的暴力算法……

这题肯定不可以DP,那么就想想贪心和网络流。

觉得这题做法一定是贪心,因为有10410^4104这么大,肯定不是网络流啊!

到最后还是没有想出来。


正解

正解早就被我否定了!(真香)

这题的正解就是网络流啊。

接下来考虑怎么建图,按照传统套路:

建立源点SSS和汇点TTT,若状态为000,则SSS向它连一条边,否则它向TTT连一条边。

容量为它们的代价(意味着如果要割掉这条边就要付出这么多代价)

对于每个人(假设他要求将状态变为0),建一个点(记为xxx)

首先SSS向xxx连一条边,容量为收入(如果有赔钱就讲赔钱加上)。接着xxx向每个要改变的点连一条容量为无限大的边。

反之同理。

然后跑一遍最小割。答案一开始加上所有收入,减去最大流。

接着分析一下这为什么是对的。

SSS向xxx连一条边,如果xxx的要求不能达到,那么必然有一个要改变的点连向了TTT。

所以SSS向xxx连的这一条边会被割掉。

实际上我们可以看成是xxx点对那些点的限制,如果它们ororor和为000,那就不用被割,否则S→xS \to xS→x或那个点到TTT之间一定会被割掉一条。

这题网络流可以过……这是最不可思议的地方……我跑了20ms……


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 10010
#define M 2010
#define INF 2147483647
int n,m,g;
int sex[N];
struct EDGE{
int to,c;
EDGE *las;
} e[(N+M*10+M)*2];
int ne=-1;
EDGE *last[N+M+2],*cur[N+M+2];
inline void link(int u,int v,int c){
e[++ne]={v,c,last[u]};
last[u]=e+ne;
}
#define rev(ei) (e+(int(ei-e)^1))
int cnt,S,T;
int ans;
int gap[N+M+2],h[N+M+2];
bool BZ;
int dfs(int x,int s){
if (x==T)
return s;
int have=s;
for (EDGE *ei=cur[x];ei;ei=ei->las){
cur[x]=ei;
if (ei->c && h[ei->to]+1==h[x]){
int t=dfs(ei->to,min(ei->c,have));
ei->c-=t,rev(ei)->c+=t,have-=t;
if (!have)
return s;
}
}
cur[x]=last[x];
if (!--gap[h[x]])
BZ=0;
h[x]++;
gap[h[x]]++;
return s-have;
}
inline int flow(){
int res=0;
gap[0]=cnt;
memset(h,0,sizeof h);
BZ=1;
while (BZ)
res+=dfs(S,INF);
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&g);
cnt=n;S=++cnt;T=++cnt;
for (int i=1;i<=n;++i)
scanf("%d",&sex[i]);
for (int i=1;i<=n;++i){
int w;
scanf("%d",&w);
if (sex[i]==0)
link(S,i,w),link(i,S,0);
else
link(i,T,w),link(T,i,0);
}
for (int i=1;i<=m;++i){
int ns,val,k;
scanf("%d%d%d",&ns,&val,&k);
ans+=val;
++cnt;
if (ns==0){
while (k--){
int x;
scanf("%d",&x);
link(cnt,x,INF),link(x,cnt,0);
}
int gf;
scanf("%d",&gf);
link(S,cnt,val+gf*g),link(cnt,S,0);
}
else{
while (k--){
int x;
scanf("%d",&x);
link(x,cnt,INF),link(cnt,x,0);
}
int gf;
scanf("%d",&gf);
link(cnt,T,val+gf*g),link(T,cnt,0);
}
}
ans=ans-flow();
printf("%d\n",ans);
return 0;
}

总结

见到一道题,应该要想到DP、贪心、网络流。

对于网络流,我以前都会分析一下时间复杂度,再看看能不能用网络流。

可我发现我错了,原来网络流的时间复杂度一直都是玄学。

因此以后我要改变一下策略:

见到不会做的题目就用网络流!

[JZOJ4682] 【GDOI2017模拟8.11】生物学家的更多相关文章

  1. [JZOJ4684] 【GDOI2017模拟8.11】卡牌游戏

    题目 描述 题目大意 有111到2n2n2n牌,一开始分别给两个人,每人nnn张. 轮流出牌,给出对手出牌的顺序,若自己的牌更大,就记一分. 在中间的某个时刻可以改变游戏规则. 问最大的分数. 思考历 ...

  2. 【JZOJ4858】【GDOI2017模拟11.4】Walk

    题目描述 在比特镇一共有n 个街区,编号依次为1 到n,它们之间通过若干条单向道路连接. 比特镇的交通系统极具特色,除了m 条单向道路之外,每个街区还有一个编码vali,不同街区可能拥有相同的编码.如 ...

  3. 【JZOJ4848】【GDOI2017模拟11.3】永恒的契约

    题目描述 宅邸迅速的燃烧着,必须带贝蒂走出禁书库!凭着感觉,又一次直接找到禁书库的门. "你,是那个人嘛?"400年了,当初圣域建立结界时没有进入圣域,被伤了心的人工精灵贝蒂,与强 ...

  4. GMOJ5409.【GDOI2017模拟一试4.11】平行宇宙

    https://gmoj.net/senior/#main/show/5051 Solution 首先注意到每个点有且只有一条出边,也就是说这是一个环套树(森林). 那么我们可以贪心. 首先这个森林里 ...

  5. 【JZOJ 5048】【GDOI2017模拟一试4.11】IQ测试

    题目大意: 判断一个序列是否是另外一个序列删除若干个数字之后得到的. 正文: 我们可以定义两个指针,分别指向长序列和短序列. 拿样例来举例: 如果指针指的数相同,两个指针都往右跳: 如果不同,则指向长 ...

  6. [转载]如何在C++03中模拟C++11的右值引用std::move特性

    本文摘自: http://adamcavendish.is-programmer.com/posts/38190.htm 引言 众所周知,C++11 的新特性中有一个非常重要的特性,那就是 rvalu ...

  7. 「考试」noip模拟9,11,13

    9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...

  8. ZOJ 3780 - Paint the Grid Again - [模拟][第11届浙江省赛E题]

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3780 Time Limit: 2 Seconds      Me ...

  9. 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋

    题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...

随机推荐

  1. Portainer Exec Container 失败解决方案

    近日,将portainer服务挂了个域名,然后用Nginx代理的时候发现不能attach容器了,经过搜索在issue 找到解决方案 1.修改Nginx config server { listen 8 ...

  2. plugin python was not installed: Cannot download ''

    problem: plugin python was not installed: Cannot download ''........ 1. the first method of resoluti ...

  3. Jsoup 学习笔记

    这里写自定义目录标题 Jsoup 学习笔记 解析 HTML 的字符串解析 URL 解析 本地文件解析 解析数据 DOM 解析 使用选择器解析 选择器概述 选择器组合用法 过滤用法 修改数据 HTML ...

  4. 初探分布式环境的指挥官ZooKeeper

    目录 1. 从单机到集群,分布式环境中的挑战 1.1 集中式的特点 1.2 集中式的痛点 1.3 从单体到SOA的转变 1.4 分布式服务总体框架 1.5 分布式应用概述 2. ZK基本概念及核心原理 ...

  5. EFCore学习记录笔记

    1:连接slqlocaldb数据库 (1)在CMD下可以输入sqllocaldb info 查看本机安装的所有的localdb实例 (2)数据库连接字符串为:“Server=(localdb)\\MS ...

  6. boost相关函数

    1.boost::scoped_ptr是一个比较简单的智能指针,它能保证在离开作用域之后它所管理对象能被自动释放 #include <iostream> #include <boos ...

  7. Aop 简单实例

    一 , 定义aop @Aspect @Component public class MyAspect { //* com 这里有个 空格 ! @Pointcut("execution(* c ...

  8. 集群cluster概念

    集群是由两台或多台计算机(称为节点node或成员member)共同执行任务群集 集群方式: 存储集群  GFS共享存储 负载均衡  LB load balance 高可用     HA high av ...

  9. 使用OCCI操作Oracle数据库写入中文乱码

    解决方法如下: oracle::occi::Environment *pOracleOcciEnv = Environment::createEnvironment(oracle::occi::Env ...

  10. memset 初始化 不同数值 打表

    #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #in ...