SDOI2014 LIS

Posted fengxunling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2014 LIS相关的知识,希望对你有一定的参考价值。

题目链接:戳我

我们先做一个DP,就能求出来到前i位的最长上升子序列的长度(maxx[i]数组)。

然后我们考虑求最小割——给每个点拆点,如果要割掉这个点,就相当于把in[i]--out[i]这条边给割掉了。

然后如果在最长上升子序列中,该位下面可以接很多,那么就从该位代表的out向下面可以接的in连边。

然后跑最小割就行了QAQ

但是......之后还需要求字典序最小的最小割方案。
那么我们先把边从小到大排个序,然后把所有可能割边都捞出来,贪心地选择。
但是有一个问题,就是我们选择了一个边之后,它会对我们之后的决策产生影响(比如说,本来应该选的边可以不选了)
所以我们要强行退流(具体操作可以看代码)。我们知道选了这条边之后,这条边的可替代品就不需要选了,这些可替代它的边显然是存在于S-u,v-T之间的。所以我们直接退掉他们满流边的流量就行啦!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define S 0
#define T 2*n+1
#define MAXN 1510
#define INF 0x3f3f3f3f
using namespace std;
inline int read()

    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')if(ch==-1)f=-1;ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48);ch=getchar();
    return x*f;

int TT,n,t=1,cnt,kkk;
int num[MAXN];
int ans[MAXN],in[MAXN],out[MAXN],done[MAXN];
int head[MAXN],cur[MAXN],dis[MAXN],dp[MAXN][MAXN],maxx[MAXN];
struct Nodeint id,a,b,c;node[MAXN];
struct Edgeint nxt,to,dis;edge[MAXN*MAXN*2];
inline void add(int from,int to,int dis)

//  printf("[%d %d] %d\n",from,to,dis);
    edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
    edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,head[to]=t;

inline bool check(int s,int t)

    queue<int>q;
    memset(done,0,sizeof(done));
    q.push(s);done[s]=1;
    while(!q.empty())
    
        int u=q.front();q.pop();
        if(u==t) return true;
        for(int i=head[u];i;i=edge[i].nxt)
        
            int v=edge[i].to;
            if(edge[i].dis&&done[v]==0) 
                q.push(v),done[v]=1;
        
    
    return false;

inline bool bfs(int s,int t)

    queue<int>q;
    memset(dis,0x3f,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    q.push(s);dis[s]=0;
    while(!q.empty())
    
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=edge[i].nxt)
        
            int v=edge[i].to;
            if(edge[i].dis&&dis[v]==0x3f3f3f3f)
            
                dis[v]=dis[u]+1;
                q.push(v);
            
        
    
    if(dis[t]==0x3f3f3f3f) return false;
    return true;

inline int dfs(int x,int t,int f)

    if(!f||x==t) return f;
    int used=0,w;
    for(int i=cur[x];i;i=edge[i].nxt)
    
        int v=edge[i].to;
        cur[x]=i;
        if(dis[v]==dis[x]+1&&(w=dfs(v,t,min(edge[i].dis,f))))
        
            edge[i].dis-=w;
            edge[i^1].dis+=w;
            used+=w,f-=w;
            if(!f) break;
        
    
    return used;

inline int dinic(int s,int t)

    int cur_ans=0;
    while(bfs(s,t)) cur_ans+=dfs(s,t,INF);
    return cur_ans;

inline void pre()

    for(int i=1;i<=n;i++)
    
        maxx[i]=1;
        for(int j=1;j<i;j++)
            if(node[i].a>node[j].a)
                maxx[i]=max(maxx[i],maxx[j]+1);
       
    for(int i=1;i<=n;i++) kkk=max(kkk,maxx[i]);

inline void add_edge()

    for(int i=1;i<=n;i++) in[i]=i;
    for(int i=n+1;i<=2*n;i++) out[i-n]=i;
    for(int i=1;i<=n;i++) add(in[i],out[i],node[i].b),num[i]=t-1;
    for(int i=1;i<=n;i++)
    
        for(int j=1;j<i;j++)
        
            if(maxx[j]+1==maxx[i]&&node[j].a<node[i].a)
                add(out[j],in[i],INF);
        
    
    for(int i=1;i<=n;i++) if(maxx[i]==1) add(S,in[i],INF);
    for(int i=1;i<=n;i++) if(maxx[i]==kkk) add(out[i],T,INF);

inline bool cmp(struct Node x,struct Node y)return x.c<y.c;
inline void solve()

    for(int i=1;i<=n;i++)
    
        int x=node[i].id;
        if(check(in[x],out[x])) continue;
        ans[++cnt]=x;
        while(bfs(T,out[x])) dfs(T,out[x],INF);
        while(bfs(in[x],S)) dfs(in[x],S,INF);
        edge[num[x]].dis=0,edge[num[x]^1].dis=0;
    

int main()

    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    TT=read();
    while(TT--)
    
        memset(head,0,sizeof(head));
        cnt=0,kkk=0;
        t=1;
        n=read();
        for(int i=1;i<=n;i++) node[i].a=read();
        for(int i=1;i<=n;i++) node[i].b=read();
        for(int i=1;i<=n;i++) node[i].c=read();
        pre();
        add_edge();
        printf("%d ",dinic(S,T));
        for(int i=1;i<=n;i++) node[i].id=i;
        sort(&node[1],&node[n+1],cmp);
        solve();
        printf("%d\n",cnt);
        sort(&ans[1],&ans[cnt+1]);
        for(int i=1;i<=cnt;i++) printf("%d ",ans[i]); puts("");
    
    return 0;

以上是关于SDOI2014 LIS的主要内容,如果未能解决你的问题,请参考以下文章

3532: [Sdoi2014]Lis 最小字典序最小割

[题解]SDOI2014LIS

[BZOJ3532][SDOI2014]LIS

SDOI2014 LIS

[SDOI2014]LIS

SDOI2014 LIS