zoukankan      html  css  js  c++  java
  • 洛谷P2766 最长递增子序列问题

    https://www.luogu.org/problemnew/show/P2766

    注:题目描述有误,本题求的是最长不下降子序列

    方案无限多时输出 n

    网络流求方案数,长见识了

    第一问:

    DP

    同时得到f[i] 表示 以第i个数为开头的最长不下降子序列长度

    第二问:

    每个点拆出2个点 i<<1,i<<1|1,之间连流量为1的边

    如果f[i]==最长长度,源点向i<<1连流量为1的边

    如果f[i]==1,i<<1|1向汇点连流量为1的边

    如果 i<j && f[i]==f[j]+1   i<<1 向j<<1|1 连流量为1的边

    这样每一条增广路就是一个方案

    第三问:

    源点向1<<1,向n<<1连的边,

    1<<1|1,n<<1|1向汇点连的边,

    1<<1与1<<1|1,n<<1与n<<1|1 之间的边

    流量改为inf

    小错误:

    特判序列为单调下降序列

    因为 源点会向每个1<<1连流量为inf 的边

    1<<1|1又会向汇点连inf的边

    这样导致第三问跑出负无穷,第9、10 测试点挂了的可能是这个原因 

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 1011
    #define M 300001
    const int inf=2e9;
    
    int n;
    int a[501];
    
    int max_len;
    int f[501];
    
    int tot=1;
    int front[N],to[M<<1],nxt[M<<1],val[M<<1],from[M<<1];
    
    int lev[N],num[N];
    int path[N];
    int cur[N];
    
    int src,decc;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } 
    }
    
    void dp()
    {
        int mx;
        for(int i=n;i;--i)
        {
            mx=0;
            for(int j=i+1;j<=n;++j)
                if(a[j]>=a[i]) mx=max(mx,f[j]);
            f[i]=mx+1;
            max_len=max(max_len,f[i]);
        }
        cout<<max_len;
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; from[tot]=u;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=0; from[tot]=v;
    //    cout<<u<<' '<<v<<' '<<w<<'
    ';
    }
    
    
    void build()
    {
        for(int i=1;i<=n;++i) add(i<<1,i<<1|1,1);
        for(int i=1;i<=n;++i)
            if(f[i]==max_len) add(src,i<<1,1);
        for(int i=1;i<=n;++i)
            if(f[i]==1) add(i<<1|1,decc,1);
        for(int i=1;i<=n;++i)
            for(int j=1;j<i;++j)
                if(a[j]<=a[i] && f[i]==f[j]-1) add(j<<1|1,i<<1,1);
    }
    
    void rebuild()
    {
        tot=1;
        memset(front,0,sizeof(front));
        
        add(1<<1,1<<1|1,inf);
        add(n<<1,n<<1|1,inf);
        for(int i=2;i<n;++i) add(i<<1,i<<1|1,1);
        
        if(f[1]==max_len) add(src,1<<1,inf);
        if(f[n]==max_len) add(src,n<<1,inf);
        for(int i=2;i<n;++i)
            if(f[i]==max_len) add(src,i<<1,1);
            
        if(f[1]==1) add(1<<1|1,decc,inf);
        if(f[n]==1) add(n<<1|1,decc,inf);
        for(int i=2;i<n;++i)
            if(f[i]==1) add(i<<1|1,decc,1);
            
        for(int i=1;i<=n;++i)
            for(int j=1;j<i;++j)
                if(a[j]<=a[i] && f[i]==f[j]-1) add(j<<1|1,i<<1,1);
    }
    
    bool bfs()
    {
        for(int i=src;i<=decc;++i) lev[i]=decc;
        queue<int>q;
        q.push(decc);
        lev[decc]=0;
        int now,t;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==decc && val[i^1]) 
                {
                    lev[t]=lev[now]+1;
                    q.push(t);
                }
            }
        }
        return lev[src]!=decc;
    }
    
    int augment()
    {
        int flow=inf,now=decc;
        int i;
        while(now!=src)
        {
            i=path[now];
            flow=min(flow,val[i]);
            now=from[i];
        }
        now=decc;
        while(now!=src)
        {
            i=path[now];
            val[i]-=flow;
            val[i^1]+=flow;
            now=from[i];
        }
        return flow;
    } 
    
    void isap()
    {
        if(!bfs()) 
        {
            cout<<'
    '<<0;
            return;
        }
        memset(num,0,sizeof(num));
        for(int i=src;i<=decc;++i) num[lev[i]]++;
        int flow=0;
        int now=src,t;
        while(lev[src]<decc)
        {
            if(now==decc)
            {
                flow+=augment();
                now=src;
            }
            bool advanced=false;
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==lev[now]-1 && val[i])
                {
                    advanced=true;
                    path[t]=i;
                    cur[now]=i;
                    now=t;
                    break;
                }
            }
            if(!advanced)
            {
                int mi=decc;
                for(int i=front[now];i;i=nxt[i])
                    if(val[i]) mi=min(mi,lev[to[i]]);
                if(!num[--lev[now]]) break;
                num[lev[now]=mi+1]++;
                cur[now]=front[now];
                if(now!=src) now=from[path[now]];
            }
        }
        cout<<'
    '<<flow;
    }
    
    int main()
    {
        read(n);
        src=1; decc=(n<<1|1)+1;
        for(int i=1;i<=n;++i) read(a[i]);
        dp();
        if(max_len==1)
        {
            cout<<'
    '<<n<<'
    '<<n;
            return 0;
        }
        build();
        isap();
        rebuild();
        isap();
    }

    题目描述

    «问题描述:

    给定正整数序列x1,...,xn 。

    (1)计算其最长递增子序列的长度s。

    (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。

    (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。

    «编程任务:

    设计有效算法完成(1)(2)(3)提出的计算任务。

    输入输出格式

    输入格式:

    第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。

    输出格式:

    第1 行是最长递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。

    输入输出样例

    输入样例#1: 复制
    4
    3 6 2 5
    输出样例#1: 复制
    2
    2
    3

    说明

    nle 500n500

  • 相关阅读:
    【乱侃】How do they look them ?
    【softeware】Messy code,some bug of Youdao notebook in EN win7
    【随谈】designing the login page of our project
    【web】Ad in security code, making good use of resource
    SQL数据库内存设置篇
    关系数据库的查询优化策略
    利用SQL未公开的存储过程实现分页
    sql语句总结
    sql中使用cmd命令注销登录用户
    SQLServer 分页存储过程
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8035164.html
Copyright © 2011-2022 走看看