Time Limit: 1000 ms Memory Limit: 512 MB

Description

​ 从前,有一只懒猫叫CJB。每个小时,这只猫要么在睡觉,要么在吃东西,但不能一边睡觉一边吃东西,并且这只猫会在一整个小时干同一件事情。

​ 对于接下来的n个小时,CJB知道他在那n个小时睡觉和吃东西的快乐值。

​ 为了健♂康♀地生活,在任意的连续 k个整小时内,CJB要有至少\(m_s\)小时睡觉,至少\(m_e\)个小时在吃东西。也就是说一共有 n−k+1段的 k小时需要满足上述条件。

你的任务是告诉CJB他接下来n个小时能获得的最大快乐值是多少。

Input

​ 第一行四个整数 \(n,k,ms,me(1≤k≤n≤1000,0≤m_s,m_e≤k,m_s+m_e≤k)\),含义如题目所述。

​ 第二行包含 n个整数 \(s_1,s_2,...,s_n(0≤s_i≤10^9)\),表示每个小时CJB睡觉能获得的快乐值。

​ 第三行包含 n个整数 \(e_1,e_2,...,e_n(0≤e_i≤10^9)\),表示每个小时CJB吃东西能获得的快乐值。

Output

输出一个整数,表示CJB能获得的最大快乐值。

Sample Input

10 4 1 2
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1

Sample Output

69

HINT

​ 【样例解释】

​ CJB在接下来的10个小时是这样的(S表示睡觉,E表示吃东西):EEESESEESS

​ 【数据范围与约定】

​ 30%的数据中, 1≤n≤10

​ 100%的数据中, 1≤n≤1000


吐槽

这题好神啊哈哈哈qwq(好吧虽然好像印象中之前做过类似的费用流的题目。。但是当时并没有搞太懂所以看到这题的时候根本没有往那边去想qwq菜醒)

然而为什么网上说是。。单纯形裸题??好吧听起来很棒但是并不会单纯形qwq

所以还是写费用流吧嗯qwq

正题

这里要用到一种特殊的建模方式!十分巧妙啊ovo

具体介绍戳这里(没错就是比较长不拎出来对不起自己嗯)

首先假设这只懒猫一直在睡觉,然后我们再决策哪些天数需要改成吃东西

用\(x_i =0\)表示这只猫第\(i\)天在睡觉,\(x_i=1\)表示在吃东西,那么我们可以列出这样的不等式组

\[\begin{aligned}
&m_e<=x_1+x_2+x_3+...+x_k<=k-m_s\\
&m_e<=x_2+x_3+x_4+...+x_{k+1}<=k-ms\\
&...\\
&m_e<=x_{n-k+1}+x_{n-k+2}+x_{n-k+3}+...+x_n<=k-m_s\\
\end{aligned}
\]

用同样的方法将这些不等式组变成等式,其中辅助变量\(0<=y_i<=k-m_s-m_e\)

\[\begin{aligned}
&x_1+x_2+x_3+...+x_k+y_1=k-m_s\\
&x_2+x_3+x_4+...+x_{k+1}+y_2=k-m_s\\
&...\\
&x_{n-k+1}+x_{n-k+2}+...+x_n=k-m_s\\
\end{aligned}
\]

同样的套路,在一头一尾加上两个0=0等式,用上面的减去下面的得到:

\[\begin{aligned}
&x_1+x_2+x_3+...+x_k+y_1=k-m_s\\
&x_1-x_{k+1}+y_1-y_2=0\\
&x_2-x_{k+2}+y_2-y_3=0\\
&...\\
&x_{n-k}-x_{n}+y_{n-k}-y_{n-k+1}=0\\
&x_{n_k+1}+x_{n-k+2}+...+x_{n}+y_{n-k+1}=k-m_s\\
\end{aligned}
\]

(啊?想用下面的减去下面的?额一样的反正都可以)

然后按照套路:

\[\begin{aligned}
&x_1-x_{k+1}+y_1-y_2=0\\
&x_2-x_{k+2}+y_2-y_3=0\\
&...\\
&x_{n-k}-x_{n}+y_{n-k}-y_{n-k+1}=0\\
&(k-m_s)-x_1-x_2-x_3-...-x_k-y_1=0\\
&x_{n_k+1}+x_{n-k+2}+...+x_{n}+y_{n-k+1}-(k-m_s)=0\\
\end{aligned}
\]

(其实倒数第二条式子是第1条式子和第0条式子相减得到,的但是为了和后面的代码中的编号对应我们稍微改变一下位置)

观察一下,变成了这个样子之后所有式子加起来变量和常数项就都抵消掉了,满足流量平衡

那么就用和bzoj1061同样的方式把每个等式看成一个点,负的流出正的流入就好啦

跑完一遍最小费用最大流之后,最终的\(ans\)就是$\sum\limits_{i=1}^{n}s_i - $最小费用

然而这并没有结束

首先是,这题的\(x_i\)和\(y_i\)是有范围的!

\(y_i\)的范围上面写了就是\(0<=y_i<=k-m_s-m_e\)

而\(x_i\)的话要么是\(0\)要么是\(1\)

所以两个变量对应的边的容量应该分别为\(k-m_s-m_e\)和\(1\)

再有就是,如果稍微想一下等式之间的连边情况,会发现。。\(k<n-k\)和\(k>n-k\)这两种情况是不一样的!

所以说,这题还要分类讨论

然而具体的连边方式。。写起来十分混乱不如自己去推qwq,详情可以参考代码

(注意,代码中将上面的第一条等式放在了倒数第二条,所以编号为\(n-k+1\),最后一条等式的编号为\(n-k+2\),其他的等式依次为\(1\)到\(n-k\))

这里只讲一下大概要连哪几类边,下面所说的编号顺序按照最终给出的等式组来(也就是代码中的顺序):

  1. 第一种\(y\)边。从\(i+1\)连到\(i\)
  2. 第二种\(y\)边。从最后一条等式连到第\(1\)条等式,从\(n-k\)条等式连到倒数第二条等式
  3. 源点到\(n-k+1\)的边,汇点到\(n-k+2\)的边
  4. 第\(1\)到\(n-k\)条等式中每个正的\(x\)的边。
  5. 第\(1\)到\(n-k\)条等式中每个负的\(x\)的边。

稍微提一下,前3类是固定的,第4和第5类又可以分第\(1\)到\(n-k\)条连到最后两条,和\(1\)到\(n-k\)条里面自己乱连两小类,具体就\(k\)和\(n\)的大小关系而定

自己写的时候把\(k=n-k\)的情况也分出来了,可能是。。可以合并的不过不管了反正这么写也不影响正确性

然后就很愉快(个鬼啊分类讨论这种东西)滴做完啦ovo


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
#define F 1
using namespace std;
const int N=10010;
const int M=1000010;
const ll inf=1e15;
struct xxx{
int y,next,op;
ll c,r;
}a[M*10];
queue<int> q;
int h[N];
ll e[N],s[N];
ll pre[M],mn[N],pred[M];
ll d[N];
ll ans,sum;
bool vis[N];
int n,m,vs,vt,tot;
ll k,ms,me;
int add(int x,int y,int r,ll c);
int spfa();
int build(); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
#endif
scanf("%d%lld%lld%lld",&n,&k,&ms,&me);
vs=0; vt=n-k+3;
sum=0;
for (int i=1;i<=n;++i) scanf("%lld",s+i),sum+=s[i];
for (int i=1;i<=n;++i) scanf("%lld",e+i);
build();
ans=0;
while (spfa());
printf("%lld\n",sum+ans);
} int add(int x,int y,int r,ll c){
a[++tot].y=y; a[tot].next=h[x]; h[x]=tot; a[tot].r=r; a[tot].op=tot+1; a[tot].c=c;
a[++tot].y=x; a[tot].next=h[y]; h[y]=tot; a[tot].r=0; a[tot].op=tot-1; a[tot].c=-c;
} int spfa(){
while (!q.empty()) q.pop();
for (int i=vs;i<=vt;++i) d[i]=-inf,vis[i]=false,mn[i]=inf;
q.push(vs); vis[vs]=1; d[vs]=0;
mn[vs]=inf; pre[vs]=-1; pred[vs]=-1;
int v,u;
while (!q.empty()){
v=q.front(); q.pop();
for (int i=h[v];i!=-1;i=a[i].next){
u=a[i].y;
if (!a[i].r) continue;
if (d[u]<d[v]+a[i].c){
pre[u]=i; pred[u]=v;
mn[u]=min(mn[v],a[i].r);
d[u]=d[v]+a[i].c;
if (!vis[u])
vis[u]=1,q.push(u);
}
}
vis[v]=false;
}
if (d[vt]==-inf) return false;
ll flow=mn[vt];
ans+=flow*d[vt];
u=vt;
while (pre[u]!=-1){
a[pre[u]].r-=flow;
a[a[pre[u]].op].r+=flow;
u=pred[u];
}
return true;
} int build(){
memset(h,-1,sizeof(h));
if (k<n-k){
/*X*/
for (int i=1;i<=k;++i) add(n-k+1,i,F,e[i]-s[i]);
for (int i=n-2*k+1;i<=n-k;++i) add(i,n-k+2,F,e[i+k]-s[i+k]);
for (int i=1;i<=n-2*k;++i) add(i,i+k,F,e[i+k]-s[i+k]);
}
else if (k==n-k){
/*X*/
for (int i=1;i<=n-k;++i) add(n-k+1,i,F,e[i]-s[i]);
for (int i=1;i<=n-k;++i) add(i,n-k+2,F,e[i+k]-s[i+k]);
}
else{
/*X*/
for (int i=1;i<=n-k;++i) add(n-k+1,i,F,e[i]-s[i]);
for (int i=1;i<=n-k;++i) add(i,n-k+2,F,e[i+k]-s[i+k]);
for (int i=n-k+1;i<=k;++i) add(n-k+1,n-k+2,F,e[i]-s[i]);
}
/*Y*/for (int i=1;i<=n-k-1;++i) add(i,i+1,k-ms-me,0);
/*Y*/add(n-k+1,1,k-ms-me,0); add(n-k,n-k+2,k-ms-me,0);
/*X*/add(vs,n-k+1,k-ms,0); add(n-k+2,vt,k-ms,0);
}

【xsy2115】Delight for a Cat的更多相关文章

  1. 【命令】Linux常用命令

    常用指令 ls 显示文件或目录ls -f 查看目录中的文件 ls -l 列出文件详细信息l(list) ls -a 列出当前目录下所有文件及目录,包括隐藏的a(all)ls *[0-9]* 显示包含数 ...

  2. 【转】Linux学习(1)-常用快捷键、文件管理和查询

    原文链接:http://www.cnblogs.com/zhaopei/p/7397402.html 有话要说 为什么要用Linux?要用Linux的原因太多,想说说不完啊. 如果你说用Linux只是 ...

  3. 【BZOJ4842】[Neerc2016]Delight for a Cat 线性规划+费用流

    [BZOJ4842][Neerc2016]Delight for a Cat Description ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打 ...

  4. 【Linux】cat命令

    用途 cat用于将一个档案的内容连续的打印在屏幕上 全称 cat的全称是Conctaenate 参数 -A :相当于-vTE的整合选项,可列出一些特殊字符而不是空白而已 -b :列出行号,仅针对非空白 ...

  5. 【转】大众点评CAT开源监控系统剖析

    https://www.cnblogs.com/yeahwell/p/cat.html 参考文档: 大众点评的实时监控系统分析(一) CAT_source_analyze 透过CAT,来看分布式实时监 ...

  6. 【整理】Linux下中文检索引擎coreseek4安装,以及PHP使用sphinx的三种方式(sphinxapi,sphinx的php扩展,SphinxSe作为mysql存储引擎)

          一,软件准备 coreseek4.1 (包含coreseek测试版和mmseg最新版本,以及测试数据包[内置中文分词与搜索.单字切分.mysql数据源.python数据源.RT实时索引等测 ...

  7. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  8. 【Android】一种提高Android应用进程存活率新方法

    [Android]一种提高Android应用进程存活率新方法 SkySeraph Jun. 19st 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph ...

  9. XiangBai——【AAAI2017】TextBoxes_A Fast Text Detector with a Single Deep Neural Network

    XiangBai--[AAAI2017]TextBoxes:A Fast Text Detector with a Single Deep Neural Network 目录 作者和相关链接 方法概括 ...

随机推荐

  1. centos 6.* 配置端口

    vi /etc/sysconfig/iptables 将 -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT     (允 ...

  2. Linux 环境下程序不间断运行

    一.背景     在linux命令行中执行程序,程序通常会占用当前终端,如果不启动新的终端就没法执行其他操作.简单可以通过'&'将程序放到后台执行,但是这种方法有个问题就是,一旦连接远程服务器 ...

  3. java-redis初探

    一.Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的 ...

  4. SpringBoot 中常用注解

    本篇博文将介绍几种SpringBoot 中常用注解 其中,各注解的作用为: @PathVaribale 获取url中的数据 @RequestParam 获取请求参数的值 @GetMapping 组合注 ...

  5. Windows系统上Redis的安装

    Redis 安装 Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统 ...

  6. 原创:实现ehcache动态创建cache,以及超期判断的具体逻辑

    当前最常用的三个缓存组件:ehcache.redis.memcached 其中,ehcache与应用共同运行于JVM中,属于嵌入式组件,运行效率最高,因此常被用于实现一级缓存. 在更复杂的一些系统中, ...

  7. Java线程的六种状态

    java线程有很多种状态,最主要的有六种,被创建.运行.睡眠.等待.阻塞以及消亡六种,也有很多归结为5种,把睡眠以及等待归结为冻结: 被创建:就是线程被创建,就是new thread()之后就是创建一 ...

  8. 吾八哥学Selenium(三):操作复选框checkbox/单选框radio的方法

    复选框checkbox和单选框radio是web网站里经常会使用到的两个控件,那么在web自动化测试的时候如何利用Selenium来操作这俩控件呢?今天我们就来简单入门练习一下! html测试页面代码 ...

  9. 将DataSet转化成XML格式的String类型,再转化回来。

    /// <summary> /// 获取DataSet的Xml格式 /// </summary> public static string GetDataSetXml(this ...

  10. 转 Caffe学习系列(3):视觉层(Vision Layers)及参数

    所有的层都具有的参数,如name, type, bottom, top和transform_param请参看我的前一篇文章:Caffe学习系列(2):数据层及参数 本文只讲解视觉层(Vision La ...