码迷,mamicode.com
首页 > 其他好文 > 详细

P2766 最长不下降子序列问题

时间:2020-02-22 09:27:34      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:flow   sign   注意   open   情况   because   type   unsigned   bool   

我学oi是为了什么呢?

wjsjdnghnhzyqw

正文

话说,这个题的第一问不就是送的吗。求一个 LIS ,在数据量不大的时候,做一个朴素的 \(n^2\) ,就好了完全没必要用维护最后一个的 \(n \log n\)

然后,我想的就是如何建图,话说其实第二问的做出来了,第三问不就是送的吗

我们来正经的说说,这个题怎么做

  1. 先是因为每个数只能用一次,然后,就考虑拆点

  2. because 我们要统计的是 LIS ,所以有在 \(i>j\ ,\ f[j]==f[i]+1\ ,\ a[j]<=a[i]\) 时可以连一条 \(j->i \ flow=1\)的边,注意后面的点连前面的点。其实去所谓
  3. 我们对于 f[i]=1,f[i]=ans 的点分别连向 st

之后找猫画虎的改动一个地方就可以写出第三问

然后,你可以得到一个74pts代码

/* make by ltao */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <time.h>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <fstream>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define inf 1e5
#define sz 666666
#define fake int
#define get() getchar()
using namespace std;
int read(){
    int x=0;char ch=get();bool f=0;
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=1;
        ch=get();
    }
    while(ch<='9'&&ch>='0'){
        x=(x<<1)+(x<<3)+(ch-'0');
        ch=get();
    }
    return f?-x:x;
}
const int Maxn=1e4+11,Maxm=2*1e5+111;
int n,a[Maxn],h[Maxn],s,t,cnt,f[Maxn],maxflow,ans,dep[Maxn],cur[Maxn];
struct Edge{
    int to,flow,lac;
    void insert(int x,int y,int z){
        to=y;
        lac=h[x];
        h[x]=cnt++;
        flow=z;
    }
}edge[Maxm];
bool bfs(int s,int t){
    queue<int> q;q.push(s);
    memset(dep,-1,sizeof dep);dep[s]=0;
    memcpy(cur,h,sizeof cur);
    while(!q.empty()){
        int fr=q.front();q.pop();
        for(int i=h[fr];i!=-1;i=edge[i].lac){
            int to=edge[i].to;
            if(!edge[i].flow||dep[to]!=-1) continue;
            dep[to]=dep[fr]+1;
            q.push(to);
            if(to==t){
                while(!q.empty()) q.pop();
                return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int min1){
    if(u==t) return min1;
    int sum=min1;
    for(int i=cur[u];i!=-1;i=edge[i].lac){
        int to=edge[i].to;
        if(!edge[i].flow||dep[to]!=dep[u]+1) continue;
        int ret=dfs(to,min(sum,edge[i].flow));
        cur[u]=i;
        edge[i].flow-=ret;edge[i^1].flow+=ret;sum-=ret;
        if(!sum) break; 
    }
    return min1-sum;
}
void Dinic(int s,int t){
    while(bfs(s,t)) 
        maxflow+=dfs(s,0x3f3f3f3f);
}
int main(){
    freopen("c.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++){
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]<=a[i]) f[i]=max(f[i],f[j]+1);
        ans=max(ans,f[i]);
    }
    printf("%d\n",ans);s=0;t=n*2+1;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
        if(f[i]==1) edge[cnt].insert(s,i*2-1,1),edge[cnt].insert(i*2-1,s,0);
        else if(f[i]==ans) edge[cnt].insert(i*2,t,1),edge[cnt].insert(t,i*2,0);
    for(int i=1;i<=n;i++)
        edge[cnt].insert(i*2-1,i*2,1),edge[cnt].insert(i*2,i*2-1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[j]<=a[i]&&f[i]==f[j]+1){
                edge[cnt].insert(j*2,i*2-1,1);
                edge[cnt].insert(i*2-1,j*2,0);
            }
    Dinic(s,t);
    printf("%d\n",maxflow);
    maxflow=0;memset(h,-1,sizeof h);cnt=0;
    for(int i=1;i<=n;i++){
        if(f[i]==1)
            edge[cnt].insert(s,i*2-1,(i==1||i==n)?inf:1),edge[cnt].insert(i*2-1,s,0);
        if(f[i]==ans)
            edge[cnt].insert(i*2,t,(i==1||i==n)?inf:1),edge[cnt].insert(t,i*2,0);
    }
    for(int i=1;i<=n;i++)
        edge[cnt].insert(i*2-1,i*2,(i==1||i==n)?inf:1),edge[cnt].insert(i*2,i*2-1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[j]<=a[i]&&f[i]==f[j]+1){
                edge[cnt].insert(j*2,i*2-1,1);
                edge[cnt].insert(i*2-1,j*2,0);
            }
    Dinic(s,t);
    printf("%d",maxflow);
    return 0;
}

因为你忘考虑 ans=1 的情况了。。

所以我们在此处加上特判

    if(ans==1){
        printf("%d\n%d",n,n);
        return 0;
    }

然后,你就可以愉快的AC了,咕

技术图片

上帝给了我oi,我要好好去珍惜

P2766 最长不下降子序列问题

标签:flow   sign   注意   open   情况   because   type   unsigned   bool   

原文地址:https://www.cnblogs.com/zhltao/p/12343845.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!