题目

描述

题目大意

有一个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. DLL劫持技术例子: HijackDll

    控制台程序:DllLoader Dll加载器,用于动态加载目标Dll,并动态调用目标函数 #include <cstdio> #include <windows.h> type ...

  2. 开发中运行mysql脚本,发现提示mysql提示Column count doesn't match value count at row 1错误

    开发中运行mysql脚本,发现提示mysql提示Column count doesn't match value count at row 1错误, 调试后发现是由于写的SQL语句里列的数目和后面的值 ...

  3. Java 网络编程(1):使用 NetworkInterface 获得本机在局域网内的 IP 地址

    原文地址:https://segmentfault.com/a/1190000007462741 1.问题提出 在使用 Java 开发网络程序时,有时候我们需要知道本机在局域网中的 IP 地址.很常见 ...

  4. [kuangbin带你飞]专题一 简单搜索 - L - Oil Deposits

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #i ...

  5. 利用IK分词器,自定义分词规则

    IK分词源码下载地址:https://code.google.com/p/ik-analyzer/downloads/list lucene源码下载地址:http://www.eu.apache.or ...

  6. jmeter 实战

    JMeter 接口测试 什么是接口测试 概念 内部接口 方法与方法之间的交互 模块与模块之间的交互 一种调用对外包装的接口 Web接口分类 web接口分类:https.http.webService ...

  7. 针对Java集合类的小总结

    Java集合类包位于java.util下,有很多常用的数据结构:数组.链表.队列.栈.哈希表等等.了解不同的集合类的特性在开发过程中是比较重要的,感谢@兰亭风雨的专栏分析,这里我也根据自己的理解做轻度 ...

  8. js数组方法 slice()和splice()

    说实在我之前都不怎么分的清这个两个函数,因为这两个函数名字那么像,经常我就弄混了,平常使用的时候都先查一下我需要使用的实际是哪个函数.这样不说很浪费时间,但是也是影响了开发效率,所以我决定今天就彻底区 ...

  9. 用多线程发送邮箱(一次给一个用户发送N封邮件)

    前台不用写,后台执行方法就可以了. namespace SendMail { public partial class SendMail_Page : System.Web.UI.Page { pro ...

  10. Java中逗号运算符的使用

    今天看到一道面试题,题目如下: 题目解释: 上面有一个类,有四个成员属性,以及两个构造方法(一个四个参数,一个两个参数),题目给出四个选项,问哪些选项可以满足在在四个参数的构造方法中完成x=a,y=b ...