给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。
如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。
如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
输入包含多组数据。
输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。
对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在4中的的位置,按升序输出。
1 < =N < =700 T < =5
Round 1 Day 2
P.S. LaTeX好像挂了..将就着看吧QAQ
首先我们知道,这道题要是没有最小字典序的限制的话,那就是一个裸的最小割。
但是,他有了最小字典序的限制,就不能是简简单单的一个最小割就是了,虽然第一问还是可以直接用最小割做。
我们考虑Lis DP的过程,(由于这里n<=700所以我们可以直接 O(n2) O ( n 2 ) 求Lis。)对于Lis DP的过程,其实就是一个DAG,起点就是 f[0]=0 f [ 0 ] = 0 ,终点就是每个 f[i]==max(f[1],f[2]...f[n]) f [ i ] == m a x ( f [ 1 ] , f [ 2 ] . . . f [ n ] ) 的点,由于这样的点有很多个,我们就需要建一个超级汇点,并且把 f[0]=0 f [ 0 ] = 0 当成一个超级源点。这样,我们对于所有的 i<j,a[i]<a[j],f[i]+1==f[j] i < j , a [ i ] < a [ j ] , f [ i ] + 1 == f [ j ] 的点,都 i−>j i − > j 连边,然后求出最小割就是第一问的答案。
对于第二个问题,我们先随便求出一个最小割,然后考虑什么样的边能成为割边。第一个必要条件就是满流,并且如果我们把这条边断掉,那么这条路径上的其他边就没有选的必要了。这样的话如果我们选了一条边 u−>v u − > v ,那么我们就需要把 s−>u s − > u 和 v−>t v − > t 的路径上的流量退掉,这样就一定不会选择这条路上的其他边了(这就是退流的思想)。现在要求字典序最小,那么我们就从小到大枚举边,然后判断这条边是否为割边:满流并且不存在增广路。如果符合就选择它,并且把这条路径上的流量退掉。这样我们就可以解决第二问了。
P.S. 好久没打最大流的手都生疏了,还调了我好久…
#pragma GCC optimize(3)
#include
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=7005,oo=0x3f3f3f3f;
struct Edge {
int from,to,cap,flow;
Edge(){}
Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
};
struct node {
int l,id;
inline bool operator < (const node &rhs) const {
return lint n,m,s,t,T;
vector edges;
vector<int>G[maxn],ans;
int d[maxn],cur[maxn],f[maxn],mx,cnt,a[maxn],b[maxn];
inline void init() {
ans.clear();
mx=0;
memset(f,0,sizeof f);
for(int i=1;iinline void addedge(int from,int to,int cap) {
edges.emplace_back(Edge(from,to,cap,0));
edges.emplace_back(Edge(to,from,0,0));
G[from].emplace_back(edges.size()-2);
G[to].emplace_back(edges.size()-1);
}
inline bool bfs(int s,int t) {
memset(d,-1,sizeof d);
queue<int>q;
q.push(s);
d[s]=0;
while(!q.empty()) {
int x=q.front();
q.pop();
for(unsigned i=0;iif(d[e.to]==-1&&e.cap>e.flow) {
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return d[t]!=-1;
}
inline int dfs(int x,int a,int s,int t) {
if(x==t||a==0)
return a;
int flow=0,f;
for(int& i=cur[x];i<(int)G[x].size();i++) {
Edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(a,e.cap-e.flow),s,t))>0) {
e.flow+=f;
edges[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)
break;
}
}
return flow;
}
inline int solve(int s,int t) {
int ans=0;
while(bfs(s,t)) {
memset(cur,0,sizeof cur);
ans+=dfs(s,oo,s,t);
}
return ans;
}
int main() {
read(T);
while(T--) {
init();
read(n);
s=2*n+1;
t=s+1;
for(int i=1;i<=n;i++)
read(a[i]);
for(int i=1;i<=n;i++)
read(b[i]);
for(int i=1;i<=n;i++)
read(c[i].l),c[i].id=i;
for(int i=1;i<=n;i++) {
for(int j=0;jif(a[j]1);
mx=max(mx,f[i]);
}
for(int i=1;i<=n;i++)
addedge(i,i+n,b[i]);
for(int i=1;i<=n;i++)
if(f[i]==mx)
addedge(i+n,t,oo);
for(int i=1;i<=n;i++)
if(f[i]==1)
addedge(s,i,oo);
for(int i=1;i<=n;i++)
for(int j=1;jif(f[i]==f[j]+1&&a[i]>a[j])
addedge(j+n,i,oo);
ll mc=solve(s,t);
sort(c+1,c+n+1);
for(int i=1,x;i<=n;i++) {
x=c[i].id;
if(edges[(x-1)<<1].flow!=edges[(x-1)<<1].cap||bfs(x,x+n))
continue;
//cout<<"!!!"<
ans.push_back(x);
solve(t,x+n),solve(x,s);
edges[(x-1)<<1].flow=edges[(x-1)<<1].cap;
edges[((x-1)<<1)^1].flow=edges[((x-1)<<1)^1].cap;
}
sort(ans.begin(),ans.end());
printf("%lld %d\n",mc,ans.size());
for(int i=0;iprintf ("%d%c",ans[i],i==ans.size()-1?'\n':' ');
}
return 0;
}