正题

题目链接:https://www.luogu.com.cn/problem/P3308


题目大意

三个\(n\)个数字的序列\(A,B,C\)。要求删除其中某些位置\(i\)使得\(A\)的最长上升子序列至少减少\(1\)且删去位置\(B\)的权值和最小的情况下满足删去位置的\(C\)值升序排序后字典序最小。


解题思路

首先\(B\)值最小很好求,跑一遍\(LIS\)的\(dp\),然后每个点拆成两个点,然后如果\(f[x]\)转移到\(f[y]\)是最优的就建边然后跑最小割就好了。

大体和P2766 最长不下降子序列问题差不多

也就是现在我们要求字典序最小的最小割,需要利用到最小割的性质。

如果一条边\(x,y\)是可行割,那么它满足在残量网络上\(x\)到达不了\(y\)。

首先如果\(x->y\)没有满流那么肯定不是最小割,其次如果满流了但是还有一条\(x\)到\(y\)的路径,那么证明如果走这条增广路一定可以使最大流更大,所以也不是最小割。

那么这样我们就可以判断一条边是否可行了,然后需要消去其他等价边的影响,大体方法是从\(T\)到\(y\)跑一次\(dinic\),再从\(x\)到\(S\)跑一次\(dinic\)。这个操作叫退流,这样残量网络就变成了满流边\(x->y\)的残量网络了。

先跑一次\(dinic\),然后按照\(C\)值排序,从小到大判断加入边即可。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const ll N=710*2,inf=1e18;
struct node{
ll to,next,w;
}a[N*N];
ll T,n,tot,ls[N],dep[N],A[N],B[N],C[N],f[N],p[N];
vector<ll> prt;queue<ll> q;
void addl(ll x,ll y,ll w){
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs(ll s,ll t){
while(!q.empty())q.pop();q.push(s);
memset(dep,0,sizeof(dep));dep[s]=1;
while(!q.empty()){
ll x=q.front();q.pop();
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(dep[y]||!a[i].w)continue;
dep[y]=dep[x]+1;
if(y==t)return 1;
q.push(y);
}
}
return 0;
}
ll dinic(ll x,ll t,ll flow){
if(x==t)return flow;
ll rest=0,k;
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(dep[x]+1!=dep[y]||!a[i].w)continue;
rest+=(k=dinic(y,t,min(flow-rest,a[i].w)));
a[i].w-=k;a[i^1].w+=k;
if(rest==flow)return flow;
}
if(!rest)dep[x]=0;
return rest;
}
bool cmp(ll x,ll y)
{return C[x]<C[y];}
signed main()
{
scanf("%lld",&T);
while(T--){
memset(ls,0,sizeof(ls));tot=1;
scanf("%lld",&n);
for(ll i=1;i<=n;i++)scanf("%lld",&A[i]);
for(ll i=1;i<=n;i++)scanf("%lld",&B[i]);
for(ll i=1;i<=n;i++)scanf("%lld",&C[i]);
ll maxs=0,s=2*n+1,t=s+1;
for(ll i=1;i<=n;i++){
f[i]=1;p[i]=i;
for(ll j=1;j<i;j++)
if(A[i]>A[j])f[i]=max(f[i],f[j]+1);
maxs=max(maxs,f[i]);
}
for(ll i=1;i<=n;i++){
if(f[i]==1)addl(s,i,inf);
if(f[i]==maxs)addl(i+n,t,inf);
addl(i,i+n,B[i]);
for(ll j=i+1;j<=n;j++)
if(A[i]<A[j]&&f[i]+1==f[j])
addl(i+n,j,inf);
}
ll ans=0;prt.clear();
while(bfs(s,t))
ans+=dinic(s,t,inf);
printf("%lld ",ans);
sort(p+1,p+1+n,cmp);
for(ll i=1;i<=n;i++){
ll x=p[i];
if(bfs(x,x+n))continue;
while(bfs(t,x+n))dinic(t,x+n,inf);
while(bfs(x,s))dinic(x,s,inf);
prt.push_back(x);
}
printf("%lld\n",prt.size());
sort(prt.begin(),prt.end());
for(ll i=0;i<prt.size();i++)
printf("%lld ",prt[i]);
putchar('\n');
}
return 0;
}

最新文章

  1. python 2.7 学习笔记--文件的基本操作
  2. Triangle - Delaunay Triangulator
  3. CREATE TABLE 表名 AS SELECT 语句
  4. python的paramiko源码修改了一下,写了个操作命令的日志审计 bug修改
  5. System.Linq.Dynamic 和Nhibernate
  6. 如何恢复SQL Server 中的Master库
  7. 《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇02:内购如何实现》
  8. js添加key为数字的对象,通过类似于通过访问数组的中括号形式访问对象属性
  9. The best way to use Xtool X100 PAD2 for FEM programming
  10. ASP.NET MVC和ASP.NET Core MVC中获取当前URL/Controller/Action (转载)
  11. Android MediaPlayer架构 -- 前言小知识点(一)
  12. 【资料搜集】Python学习
  13. What is the difference between concurrency, parallelism and asynchronous methods?
  14. Docker一些常用命令
  15. android中ListView控件最简单的用法
  16. 分水岭算法(理论+opencv实现)
  17. 【神经网络】自编码聚类算法--DEC (Deep Embedded Clustering)
  18. JBOSS集群和安装
  19. Virtex6 PCIe 超简版基础概念学习(二)
  20. CodeIgniter 无法上传 CSV 文件

热门文章

  1. C# prism 框架 MVVM框架 Prism系列之事件聚合器
  2. asp.net core 声明controller的方法
  3. WPF设计自定义控件
  4. 什么是挂载,Linux挂载详解
  5. JDBC中级篇——批处理和PreparedStatement对有sql缓冲区的数据库的友好,测试
  6. 多线程编程&lt;三&gt;
  7. 获取本地请求的真实IP地址
  8. 三大操作系统对比使用之&#183;Ubuntu16.04
  9. php常用的函数
  10. shell循环之跳出循环