zoukankan      html  css  js  c++  java
  • 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}{数据范围与提示})

    (nleq 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
    ",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
    ",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
    ",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;
    }
    
  • 相关阅读:
    Python-dict与set
    Python-实现对表插入百万条数据
    Python—元组tuple
    数据库查询
    python-操作MySQL数据库
    Python-类的继承
    Python-内置类属性
    Python-类的概念及使用1
    Python异常处理
    了解dto概念,什么是DTO
  • 原文地址:https://www.cnblogs.com/olinr/p/10114079.html
Copyright © 2011-2022 走看看