首页 > 其他分享 >2180. 最长递增子序列问题

2180. 最长递增子序列问题

时间:2022-11-27 11:35:04浏览次数:62  
标签:idx int 递增 2180 序列 长度 define

题目链接

2180. 最长递增子序列问题

给定正整数序列 \(x_1,\cdots,x_n\)。

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

  2. 计算从给定的序列中最多可取出多少个长度为 \(s\) 的递增子序列。(给定序列中的每个元素最多只能被取出使用一次)

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

注意:递增指非严格递增。

输入格式

第 \(1\) 行有 \(1\) 个正整数 \(n\),表示给定序列的长度。

接下来的 \(1\) 行有 \(n\) 个正整数 \(x_1,\cdots,x_n\)。

输出格式

第 \(1\) 行输出最长递增子序列的长度 \(s\)。

第 \(2\) 行输出可取出的长度为 \(s\) 的递增子序列个数。

第 \(3\) 行输出允许在取出的序列中多次使用 \(x_1\) 和 \(x_n\) 时可取出的长度为 \(s\) 的递增子序列个数。

数据范围

\(1 \le n \le 500\)

输入样例:

4
3 6 2 5

输出样例:

2
2
3

解题思路

最大流,拆点

dp 解出第一问,\(g[i]\) 表示前 \(i\) 个数以 \(a[i]\) 结尾的最长上升子序列的个数,对于 \(j< i,a[j]\leq a[i],g[i]==g[j]+1\),即 \(i\) 可以通过 \(j\) 这个点转移过来,将 \(j\) 向 \(i\) 建边,且容量为 \(1\),假设 \(LIS\) 为 \(s\),建立源点 \(S\),\(S\) 向所有 \(g[i]=1\) 的 \(i\) 连边,且容量为 \(1\),建立汇点 \(T\),所有 \(g[i]=s\) 的 \(i\) 向 \(T\) 连边,且容量为 \(1\),另外由于一个点可能会用到多次,但实际上只能用一次,即对点有限制,故需要拆点,即拆分为入点和出点,中间连一条容量为 \(1\) 的边,求解 \(S\) 到 \(T\) 的最大流即为第二问的答案,\(\color{red}{为什么?}\)由于拆点,流网络中每个点只会用一次,对应原序列中每个 \(i\) 只会用一次,且 \(S\) 到 \(T\) 的路径长度为 \(s\),可以保证原序列中所有求得的长度都为 \(s\),当 \(1\) 和 \(n\) 不受限制时,将流网络中对应的正边容量设为足够大在榨干残余网络即可

  • 时间复杂度:\(O(n^2m)\)

代码

// Problem: 最长递增子序列问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2182/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1005,M=N+250005,inf=1e9;
int n,a[N],g[N],S,T;
int h[N],ne[M],f[M],e[M],idx;
int d[N],cur[N],hh,tt,q[N];
void add(int a,int b,int c)
{
	e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
	e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs()
{
	memset(d,-1,sizeof d);
	q[0]=S;
	hh=tt=d[S]=0;
	cur[S]=h[S];
	while(hh<=tt)
	{
		int x=q[hh++];
		for(int i=h[x];~i;i=ne[i])
		{
			int y=e[i];
			if(d[y]==-1&&f[i])
			{
				d[y]=d[x]+1;
				cur[y]=h[y];
				if(y==T)return true;
				q[++tt]=y;
			}
		}
	}
	return false;
}
int dfs(int x,int limit)
{
    if(x==T)return limit;
    int flow=0;
    for(int i=cur[x];~i&&flow<limit;i=ne[i])
    {
        cur[x]=i;
        int y=e[i];
        if(d[y]==d[x]+1&&f[i])
        {
            int t=dfs(y,min(f[i],limit-flow));
            if(!t)d[y]=-1;
            f[i]-=t,f[i^1]+=t,flow+=t;
        }
    }
    return flow;
}
int dinic()
{
	int res=0,flow;
	while(bfs())while(flow=dfs(S,inf))res+=flow;
	return res;
}
int main()
{
	memset(h,-1,sizeof h);
    scanf("%d",&n);
    S=0,T=2*n+1;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int s=1;
    for(int i=1;i<=n;i++)
    {
    	g[i]=1;
    	for(int j=1;j<i;j++)
    		if(a[j]<=a[i])g[i]=max(g[i],g[j]+1),s=max(s,g[i]);
    }
    for(int i=1;i<=n;i++)
    {
    	add(i,i+n,1);
    	for(int j=1;j<i;j++)
    		if(a[j]<=a[i]&&g[i]==g[j]+1)
    			add(j+n,i,1);
    	if(g[i]==1)add(S,i,1);
    	if(g[i]==s)add(i+n,T,1);
    }
    int res=0;
    printf("%d\n%d\n",s,res=dinic());
    if(s==1)printf("%d",n);
    else
    {
    	 for(int i=0;i<idx;i+=2)
	    {
	    	int a=e[i^1],b=e[i];
	    	if(a==S&&b==1)f[i]=inf;
	    	if(a==1&&b==n+1)f[i]=inf;
	    	if(a==n+n&&b==T)f[i]=inf;
	    	if(a==n&&b==n+n)f[i]=inf;
	    }
    	printf("%d",res+dinic());	
    }
    return 0;
}

标签:idx,int,递增,2180,序列,长度,define
From: https://www.cnblogs.com/zyyun/p/16929330.html

相关文章

  • ORA-00742: 日志读取在线程 %d 序列 %d 块 %d 中检测到写入丢失情况----惜分飞
    标题:ORA-00742:日志读取在线程%d序列%d块%d中检测到写入丢失情况作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.]由于......
  • Newtonsoft.Json null值不序列化
    varjSetting=newJsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore};varjson=JsonConvert.SerializeObject(response,Formatting.Indented,j......
  • mysql jdbc反序列化利用
    参考资料https://www.anquanke.com/post/id/203086按照资料描述搭建环境,注意,如果使用8.0.28版本的mysql,服务端MySQL_Fake_Server会报错(ValueError('45isnotavalidCha......
  • Java 序列化工具
    一、Java自带的序列化Java提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据......
  • 【视频】Python用LSTM长短期记忆神经网络对不稳定降雨量时间序列进行预测分析|数据分
    全文下载链接:http://tecdat.cn/?p=23544 在本文中,长短期记忆网络——通常称为“LSTM”——是一种特殊的RNN递归神经网络,能够学习长期依赖关系。最近我们被客户要求撰写......
  • Android 序列化框架 Gson 原理分析,可以优化吗?
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。前言大家好,我是小彭。Gson是Google推出的JavaJson解析库,具有接入成本低、使用便捷、功......
  • LeetCode 300.最长递增子序列(中等)
    题目描述给你一个整数数组​​nums​​,找到其中最长严格递增子序列的长度。子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,​​[3......
  • Oracle数据库批量删除表、视图、序列、存储过程、函数脚本
    批量删除表、视图、序列、存储过程、函数前,生成对应的SQL执行脚本,然后执行生成对应的脚本即可:一、删除数据库表   --生成删除oracle数据库表的脚本语句   select......
  • 23.几种序列化方式
    什么是序列化关于序列化相信大家都很了解,在Java中我们经常就可以看到很多实体类或者 POJO 都会实现 Serializable 接口,有了解过 Serializable 接口的小伙伴应该都......
  • 时间序列 工具库学习(18)adtk模块-异常类型
    1.异常类型异常是一个广义的概念,它可以指代时间序列中许多不同类型的事件。根据具体情况,价值飙升、波动性转变、违反季节性模式等都可能是异常的或正常的。ADTK提供了一组......