P2766 最长不下降子序列问题

\(\color{#0066ff}{题目描述}\)

?问题描述:

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

(1)计算其最长不下降子序列的长度s。

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

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

?编程任务:

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

\(\color{#0066ff}{输入格式}\)

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

\(\color{#0066ff}{输出格式}\)

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

\(\color{#0066ff}{输入样例}\)

4
3 6 2 5

\(\color{#0066ff}{输出样例}\)

2
2
3

\(\color{#0066ff}{数据范围与提示}\)

\(n\leq 500\)

\(\color{#0066ff}{题解}\)

第一问大水题\(O(n^2)\),LIS,暴力就行

第二问第三问要用网络流

拆点,序列的每个点拆成<x,y>

因为我们要找最多的序列,每个长度为ans

第一问求出了f[i]为以i结尾的最长不下降子序列的长度

现在对于每个i

如果f[i]==1,则原点向\(i_x\)连容量为 1 的边

如果f[i]==ans,则\(i_y\)向汇点连容量为 1 的边

对于每一个\(i<j\),如果\(a[i] \leq a[j]\),并且\(f[j]==f[i]+1\),那么就从\(i_y\)向\(j_x\)连一条容量为1的边

对于每个i,连一条\(i_x\)到$i_y&的边

这样就保证了流过去一个,就是一个合法的序列,而且长度恰=ans,不会重复

对于第三问,因为\(a_1,a_n\)无限使用,把1和n的一些边变成inf就行了,在原基础上再跑一遍就行了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#define _ 0
#define LL long long
inline LL in()
{
    LL x=0,f=1; char ch;
    while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*f;
}
const int inf=0x7fffffff;
struct node
{
    int to,dis;
    node *nxt,*rev;
    node(int to=0,int dis=0,node *nxt=NULL):to(to),dis(dis),nxt(nxt){}
    void *operator new (size_t)
    {
        static node *S=NULL,*T=NULL;
        return (S==T&&(T=(S=new node[1024])+1024)),S++;
    }
};
typedef node* nod;
nod head[10500],cur[10500];
int dep[10500];
int n,s,t;
std::queue<int> q;
int a[10500];
inline void add(int from,int to,int dis)
{
    nod o=new node(to,dis,head[from]);
    head[from]=o;
}
inline void link(int from,int to,int dis)
{
    add(from,to,dis);
    add(to,from,0);
    head[from]->rev=head[to];
    head[to]->rev=head[from];
}
inline bool bfs()
{
    for(int i=s;i<=t;i++) dep[i]=0,cur[i]=head[i];
    dep[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int tp=q.front(); q.pop();
        for(nod i=head[tp];i;i=i->nxt)
            if(!dep[i->to]&&i->dis>0)
            {
                dep[i->to]=dep[tp]+1;
                q.push(i->to);
            }
    }
    return dep[t];
}
inline int dfs(int x,int change)
{
    if(x==t||!change) return change;
    int flow=0,ls;
    for(nod i=cur[x];i;i=i->nxt)
    {
        cur[x]=i;
        if(dep[i->to]==dep[x]+1&&(ls=dfs(i->to,std::min(change,i->dis))))
        {
            change-=ls;
            flow+=ls;
            i->dis-=ls;
            i->rev->dis+=ls;
            if(!change) break;
        }
    }
    return flow;
}
inline int dinic()
{
    int flow=0;
    while(bfs()) flow+=dfs(s,inf);
    return flow;
}
namespace partone
{
    int f[10505],ans;
    void main()
    {
        for(int i=1;i<=n;i++)
        {
            f[i]=1;
            for(int j=1;j<i;j++)
                if(a[j]<=a[i]) f[i]=std::max(f[i],f[j]+1);
            ans=std::max(ans,f[i]);
        }
        printf("%d\n",ans);
    }
}
namespace parttwo
{
    int fuc;
    using namespace partone;
    void main()
    {
        for(int i=1;i<=n;i++)
        {
            link(i,i+n,1);
            if(f[i]==1) link(s,i,1);
            if(f[i]==ans) link(i+n,t,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) link(j+n,i,1);
        printf("%d\n",fuc=dinic());
    }
}
namespace partthree
{
    using namespace partone;
    void main()
    {
        link(1,1+n,inf),link(s,1,inf);
        if(f[n]==ans) link(n+n,t,inf),link(n,n+n,inf);
        printf("%d\n",parttwo::fuc+dinic());
    }
}

int main()
{
    n=in();
    s=1,t=(n<<1)+1;
    for(int i=1;i<=n;i++) a[i]=in();
    partone::main();
    parttwo::main();
    partthree::main();
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10114079.html

时间: 2024-11-03 09:19:28

P2766 最长不下降子序列问题的相关文章

P2766 最长不下降子序列问题 网络流

link:https://www.luogu.org/problemnew/show/P2766 题意 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. 设计有效算法完成(1)(2)(3)提出的计算任务. 思路 题解来自网络流24题: [问题分析] 第一问是LIS,动态规划求解,第二问和第三问用网络最

【Luogu】P2766最长不下降子序列问题(暴力网络流)

题目链接 水题qwq,数据都那么水. 我要是出数据的人我就卡$n^3$建图. qwq. 然而这么水的题我!居!然!没!有!1!A!!还!提!交!了!五!遍!!! md从现在开始要锻炼1A率了 看我从今往后做完一道题之后至少检查TM十分钟 可恶qwq. 第一问$n^2$sbDP可解.然而你们知道我提交五遍TM是错在哪里了吗????? 我TM就错在这个pj-,sb到不能再sb的sb暴力DP上!!! 气死我了!!! 关于第二问和第三问,先拆点再拆点qwq. 先把每个点拆成入点和出点用来限制流量,然后把

网络流24题之最长不下降子序列问题

P2766 最长不下降子序列问题 题目描述 ?问题描述: 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. ?编程任务: 设计有效算法完成(1)(2)(3)提出的计算任务. n<=500 输入输出格式 输入格式: 第1 行有1个正整数n,表示给定序列的长度.接下来的1 行有n个正整数n:x1, ...

P2766 [网络流24题]最长不下降子序列问题

ha~ ?问题描述: 给定正整数序列$x_1,...,x_n$ .$n<=500$ 求(1)计算其最长不下降子序列的长度$s$. (2)计算从给定的序列中最多可取出多少个长度为$s$的不下降子序列. (3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列. (1)暴力n方解决 (2)建分层图,把图每个顶点i按照F[i]的不同分为若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长不下降子序列.由 S 向所有$ f_i =

洛谷2766:[网络流24题]最长不下降子序列问题——题解

https://www.luogu.org/problemnew/show/P2766 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. 第一问用dp求解不多说了. 考虑第二问,每个数只用一次很好办,把数拆点(入点和出点)中间连边权为1的边即可. 现在的问题就是如何让它能够跑满s个点. 我们设dp[i

swust oj 585--倒金字塔(LIS最长不下降子序列)

题目链接:http://acm.swust.edu.cn/problem/585/ Time limit(ms): 3000 Memory limit(kb): 65535 SWUST国的一支科学考察队到达了举世闻名的古埃及金字塔. 关于金字塔的建造一直是一个未解之谜, 有着“西方史学之父”之称的希罗多德认为,金字塔的建造是人力和牲畜,花费20 年时间从西奈半岛挖掘天然的石头运送到埃及堆砌而成.也有不少人认为是外星人修建的.人们发现胡夫金字塔的经线把地球分成东.西两个半球,它们的陆地面积是相等的

最长不下降子序列nlogn算法详解

今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ 这篇文章是在懂了这个问题n^2解决方案的基础上学习. 解决的问题:给定一个序列,求最长不下降子序列的长度(nlogn的算法没法求出具体的序列是什么) 定义:a[1..n]为原始序列,d[k]表示长度为k的不下降子序列末尾元素的最小值,len表示当前已知的最长子序列的长度. 初始化:d[1]=a[1]; len=1; (0个元素的时候特判一下) 现在我们已知最长的不下降子序列长度为1,末尾元素

tyvj 1049 最长不下降子序列 n^2/nlogn

P1049 最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降子序列的长度 测试样例1 输入 3 1 2 3 输出 3 备注 N小于5000for each num <=maxint 题意:中文题意 题解:不下降也就是>= n^n  dp[i] 表示前i个数的最长不下降子序列的长度 1 /*****************************

hdu 1160 FatMouse&#39;s Speed(最长不下降子序列+输出路径)

题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the s