本文将同步发布于:

题目

题目链接:洛谷 AT4695AtCoder agc031_e

题意简述

在二维平面上,有 \(n\) 颗珠宝,第 \(i\) 颗珠宝在 \((x_i,y_i)\) 的位置,价值为 \(v_i\)。

现在有一个盗贼想要偷这些珠宝。

现在给出 \(m\) 个限制约束偷的珠宝,约束有以下四种:

  • 横坐标小于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗。
  • 横坐标大于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗。
  • 纵坐标小于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗。
  • 纵坐标大于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗。

现在问你在满足这些约束的条件下,盗贼偷的珠宝的最大价值和是多少。

题解

约束与转化

这个约束有点难办,似乎并没有可能对其进行动态规划,因此我们考虑额外添加信息。

我们添加什么信息呢?考虑到限制是有关珠宝数量的,我们决定添加一个 偷珠宝的总数 的信息。

设偷珠宝 \(k\) 颗,并且珠宝按照的横坐标排序被偷的顺序编号为 \(1\sim k\),那么前两种限制条件转化如下:

  • 横坐标小于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗:

    若一个珠宝的编号 \(\texttt{id}\in[b_i+1,k]\),那么一定有 \(x_{\texttt{id}}>a_i\)。
  • 横坐标大于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗:

    若一个珠宝的编号 \(\texttt{id}\in[1,k-b_i]\),那么一定有 \(x_{\texttt{id}}<a_i\)。

同理,我们可以得出珠宝按照的纵坐标排序被偷的顺序编号为 \(1\sim k\),那么后两种限制条件转化如下:

  • 纵坐标小于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗:

    若一个珠宝的编号 \(\texttt{id}\in[b_i+1,k]\),那么一定有 \(y_{\texttt{id}}>a_i\)。
  • 纵坐标大于等于 \(a_i\) 的珠宝最多偷 \(b_i\) 颗:

    若一个珠宝的编号 \(\texttt{id}\in[1,k-b_i]\),那么一定有 \(y_{\texttt{id}}<a_i\)。

因此,我们得出,一个珠宝想要在按横坐标排序为第 \(i\),纵坐标排序为第 \(j\) 时被偷,需要满足的坐标范围。

化腐朽为神奇的网络流

考虑上面的条件也不是很好动态规划,我们需要想到一种化腐朽为神奇的算法——网络流。

由于这个题目有多个互不相关的限制:

  • 珠宝不能同时被偷两次及以上;
  • 偷的珠宝价值要最大化;

我们考虑运用费用流建立网络流模型。

因为我们要限制横坐标,所以必须要有 \(k\) 个横坐标的限制,对应 \(s\to p_{1\sim k}\),流量为 \(1\),费用为 \(0\)。。

因为我们要限制纵坐标,所以必须要有 \(k\) 个纵坐标的限制,对应 \(q_{1\sim k}\to t\),流量为 \(1\),费用为 \(0\)。

因为我们要限制一个点不能被选择多次,所以我们需要拆点限流,对应 \(a_{1\sim n}\to b_{1\sim n}\),流量为 \(1\),费用为 \(v_i\)。

考虑到我们上面需要满足的限制,按照限制加边 \(p_i\to a_j\) 和 \(b_j\to q_i\) 即可,流量为 \(1\),费用为 \(0\)。

如果上面的语言有点抽象,我们不妨画图理解。

整个建图如上所示,点数为 \(\Theta(n^2)\),边数 \(\Theta(n^2)\)。

参考程序

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
inline int read(void){
reg char ch=getchar();
reg int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();
return res;
} inline ll readll(void){
reg char ch=getchar();
reg ll res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();
return res;
} inline int max(reg int a,reg int b){
return a>b?a:b;
} inline int min(reg int a,reg int b){
return a<b?a:b;
} inline ll max(reg ll a,reg ll b){
return a>b?a:b;
} const int MAXN=80+5;
const int MAXM=320+5;
const int inf=0x3f3f3f3f; namespace Network{
const int MAXV=4*MAXN;
const int MAXE=(MAXN*MAXN*2+3*MAXN)*2;
const ll inf=0x3f3f3f3f3f3f3f3f;
int cnt,head[MAXV],to[MAXE],w[MAXE],Next[MAXE];
ll p[MAXE];
inline void Add_Edge(reg int u,reg int v,reg int len,reg ll val){
Next[++cnt]=head[u];
to[cnt]=v,w[cnt]=len,p[cnt]=val;
head[u]=cnt;
return;
}
inline void Add_Tube(reg int u,reg int v,reg int len,reg ll val){
Add_Edge(u,v,len,val);
Add_Edge(v,u,0,-val);
return;
}
bool inque[MAXV];
int cur[MAXV];
ll dis[MAXV];
queue<int> Q;
inline bool spfa(int s,reg int t){
fill(dis+s,dis+t+1,inf);
inque[s]=true,dis[s]=0,Q.push(s);
while(!Q.empty()){
reg int u=Q.front();
Q.pop();
inque[u]=false;
cur[u]=head[u];
for(reg int i=head[u];i;i=Next[i]){
int v=to[i];
if(dis[v]>dis[u]+p[i]&&w[i]){
dis[v]=dis[u]+p[i];
if(!inque[v]){
inque[v]=true;
Q.push(v);
}
}
}
}
return dis[t]!=inf;
}
bool vis[MAXV];
inline int dfs(reg int u,reg int t,reg ll lim){
if(u==t)
return lim;
vis[u]=true;
reg int flow=0;
for(reg int &i=cur[u];i;i=Next[i]){
reg int v=to[i];
if(dis[v]==dis[u]+p[i]&&w[i]&&!vis[v]){
reg int f=dfs(v,t,min(lim-flow,w[i]));
if(f){
flow+=f;
w[i]-=f,w[i^1]+=f;
if(flow==lim)
break;
}
}
}
vis[u]=false;
return flow;
}
inline pair<int,ll> dinic(reg int s,reg int t){
int res=0;
ll cost=0;
while(spfa(s,t)){
reg int flow=dfs(s,t,inf);
res+=flow,cost+=flow*dis[t];
}
return make_pair(res,cost);
}
inline void init(reg int s,reg int t){
cnt=1,fill(head+s,head+t+1,0);
return;
}
} struct Point{
int x,y;
ll v;
}; struct Limits{
char ch;
int a,b;
}; struct Interval{
int l,r;
inline Interval(reg int l=0,reg int r=0):l(l),r(r){
return;
}
inline bool in(reg int x)const{
return l<=x&&x<=r;
}
}; inline Interval cap(const Interval& a,const Interval& b){
return Interval(max(a.l,b.l),min(a.r,b.r));
} int n,m;
Point a[MAXN];
Limits b[MAXM]; int main(void){
n=read();
for(reg int i=1;i<=n;++i)
a[i].x=read(),a[i].y=read(),a[i].v=readll();
m=read();
for(reg int i=1;i<=m;++i){
do
b[i].ch=getchar();
while(!isalpha(b[i].ch));
b[i].a=read(),b[i].b=read();
}
reg ll ans=0;
for(reg int k=1;k<=n;++k){
static Interval invx[MAXN],invy[MAXN];
fill(invx+1,invx+k+1,Interval(-inf,inf));
fill(invy+1,invy+k+1,Interval(-inf,inf));
for(reg int i=1;i<=m;++i){
switch(b[i].ch){
case 'L':{
for(reg int j=b[i].b+1;j<=k;++j)
invx[j]=cap(invx[j],Interval(b[i].a+1,inf));
break;
}
case 'R':{
for(reg int j=1;j<=k-b[i].b;++j)
invx[j]=cap(invx[j],Interval(-inf,b[i].a-1));
break;
}
case 'D':{
for(reg int j=b[i].b+1;j<=k;++j)
invy[j]=cap(invy[j],Interval(b[i].a+1,inf));
break;
}
case 'U':{
for(reg int j=1;j<=k-b[i].b;++j)
invy[j]=cap(invy[j],Interval(-inf,b[i].a-1));
break;
}
}
}
reg int s=0,t=2*k+2*n+1;
Network::init(s,t);
for(reg int i=1;i<=k;++i){
Network::Add_Tube(s,i,1,0);
Network::Add_Tube(k+n+n+i,t,1,0);
}
for(reg int i=1;i<=n;++i)
Network::Add_Tube(k+i,k+n+i,1,-a[i].v);
for(reg int i=1;i<=k;++i)
for(reg int j=1;j<=n;++j){
if(invx[i].in(a[j].x))
Network::Add_Tube(i,k+j,1,0);
if(invy[i].in(a[j].y))
Network::Add_Tube(k+n+j,k+n+n+i,1,0);
}
pair<int,ll> res=Network::dinic(s,t);
if(res.first==k)
ans=max(ans,-res.second);
}
printf("%lld\n",ans);
return 0;
}

「题解」agc031_e Snuke the Phantom Thief的更多相关文章

  1. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  2. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  3. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  4. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  5. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  6. 「题解」:$Smooth$

    问题 A: Smooth 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 维护一个队列,开15个指针,对应前15个素数. 对于每一次添加数字,暴扫15个指针,将指针对应 ...

  7. 「题解」:Kill

    问题 A: Kill 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 80%算法 赛时并没有想到正解,而是选择了另一种正确性较对的贪心验证. 对于每一个怪,我们定义它的 ...

  8. 「题解」:y

    问题 B: y 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 考虑双向搜索. 定义$cal_{i,j,k}$表示当前已经搜索状态中是否存在长度为i,终点为j,搜索过边 ...

  9. 「题解」:x

    问题 A: x 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 赛时想到了正解并且对拍了很久.对拍没挂,但是评测姬表示我w0了……一脸懵逼. 不难证明,如果对于两个数字 ...

随机推荐

  1. Andrew Ng机器学习算法入门(四):阶梯下降算法

    梯度降级算法简介 之前如果需要求出最佳的线性回归模型,就需要求出代价函数的最小值.在上一篇文章中,求解的问题比较简单,只有一个简单的参数.梯度降级算法就可以用来求出代价函数最小值. 梯度降级算法的在维 ...

  2. 【JavaScript】Leetcode每日一题-在D天内送包裹的能力

    [JavaScript]Leetcode每日一题-在D天内送包裹的能力 [题目描述] 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口. 传送带上的第 i 个包裹的重量为 weights[i] ...

  3. java中的NAN和INFINITY

    java浮点数运算中有两个特殊的情况:NAN.INFINITY. 1.INFINITY: 在浮点数运算时,有时我们会遇到除数为0的情况,那java是如何解决的呢? 我们知道,在整型运算中,除数是不能为 ...

  4. 【vue-07】vue-router

    Vue-router官网 安装 vue-router是一个插件包,所以我们还是需要用npm 来进行安装.打开命令行工具,进入你的项目目录,输入下面命令. npm install vue-router ...

  5. Java前后端分离的认识

    1.原由 在网上查了关于前后端分离的资料,有所粗浅认识.记录下来,方便以后使用.以下均是个人看法,仅做参考.如有错误请指教,共同进步. 2.为什么前后端分离? ①.一个后台,可以让多种前台系统使用.后 ...

  6. Linux下为Calibre书库打中文目录名与文件名补丁

    本文由来 临近下班突然看到知乎上有篇文章是给Calibre打中文目录与文件名补丁的,想起我之前为啥放弃Calibre的--存进书库里书的名称都变成了拼音!手动找起来或者搜索工具找起来太麻烦了(有时想不 ...

  7. springboot 项目中css js 等静态资源无法访问的问题

    目录 问题场景 问题分析 问题解决 问题场景 今天在开发一个springboot 项目的时候突然发现 css js 等静态资源竟然都报404找不到,折腾了好久终于把问题都解决了,决定写篇博客,纪录总结 ...

  8. copy和deep.copy

    https://blog.csdn.net/qq_32907349/article/details/52190796 加上crossin公众号上的可变对象与不可变对象 a=[1,2,3,[4]] b= ...

  9. MSSQL·查看数据库编码格式

    阅文时长 | 0.67分钟 字数统计 | 837.6字符 主要内容 | 1.引言&背景 2.声明与参考资料 『MSSQL·查看数据库编码格式』 编写人 | SCscHero 编写时间 | 20 ...

  10. [Linux] Shell 脚本实例(超实用)

    文件操作 为文件(test.sh)增加执行权限 chmod +x test.sh 列出当前文件夹下所有文件(每行输出一个) 1 #!/bin/bash 2 dir=`ls ./` 3 for i in ...