欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

【P2766】 最长不下降子序列问题

发布时间:2025/7/14 编程问答 32 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【P2766】 最长不下降子序列问题 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

题目描述

«问题描述:

给定正整数序列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

说明/提示

n500

 


【解题思路】

  运用最小割解决问题的本质是

  找到多个问题同时存在且矛盾的情况,利用网络流找到最优的解

  于是这个问题的解决方式就能够这样解决

  首先,拆点,一个入点一个出点,考虑他们的连接过程

  因为源头流量为 1 ,于是就能够形成单一的链,保证情况独立,能够排除矛盾情况

  开头的是长度为 1 的,因为最长的能够包括所有子串,所以连接至汇点

  然后对每个符合要求,对这道题来说就是

  能够顺利组成增加一个字符串,使这个子串增长

  如果选择了这个子串之后,就能够或者这个子串相应的流量

  在最大流的性质和思想下最终也就能够得到最终答案了

  


【代码】

 

#include<cstdio> #include<queue> #include<cstring> #define ll int using namespace std; const int MAXN = 5010; const int MAXM = 200010; const ll INF = (1ll << 31) - 1; struct note {int to;int nt;int rev;ll cal; }; struct edge {note arr[MAXM];int siz;int maxn;int a[MAXN];int dp[MAXN];int st[MAXN];int dis[MAXN];int cur[MAXN];int depth[MAXN];int top;int n, m, s, t;edge(){memset(st, -1, sizeof(st));memset(depth, -1, sizeof(depth));memset(dis, -1, sizeof(dis));top = 0;}void read(){scanf("%d", &n);for (int i = 1; i <= n; i++)scanf("%d", &a[i]);}int LIS(){for (int i = 1; i <= n; i++)dp[i] = 1;for (int i = 1; i <= n; i++)for (int j = 1; j < i; j++){if (a[j] <= a[i]){dp[i] = max(dp[i], dp[j] + 1);}}maxn = -1;for (int i = 1; i <= n; i++)if (maxn < dp[i])maxn = dp[i];return maxn;}void build(){t = 2*n+2;for (int i = 1; i <= n; i++){add(i, i + n, 1);if(dp[i]==1)add(0, i, 1);if (dp[i] == maxn)add(i + n, t, 1);}for (int i = 1; i <= n; i++)for (int j = 1; j <i; j++)if (a[j] <= a[i] && dp[j] + 1 == dp[i])add(j+n, i , 1);s = 0;siz = 2 * n+1;}bool dep(){queue<int> q;q.push(s);memset(depth, -1, sizeof(depth));depth[s] = 0;while (!q.empty()){int v = q.front(); q.pop();for (int i = st[v]; i != -1; i = arr[i].nt){int to = arr[i].to;if (!arr[i].cal)continue;if (depth[to] != -1)continue;depth[to] = depth[v] + 1;q.push(to);}}return (depth[t] != -1);}void add(int x, int y, ll z){top++; arr[top] = { y,st[x],top + 1,z }; st[x] = top;top++; arr[top] = { x,st[y],top - 1,0 }; st[y] = top;}ll dfs(int now, ll val){if (now == t || !val)return val;ll flow = 0;for (int& i = cur[now]; i != -1; i = arr[i].nt){int to = arr[i].to;if (depth[to] != depth[now] + 1)continue;ll f = dfs(to, min(arr[i].cal, val));if (!f || !arr[i].cal)continue;flow += f;arr[i].cal -= f;arr[arr[i].rev].cal += f;val -= f;if (!val)return flow;}return flow;}ll dinic(){ll flow = 0;ll f;while (dep()){for (int i = 0; i <= siz; i++)cur[i] = st[i];while (f = dfs(s, INF))flow += f;}return flow;} }; edge road,tmp; int main() {road.read();//printf("**\n");printf("%d\n",road.LIS());//printf("**\n");//printf("\n"); road.build();//printf("**\n");tmp = road;printf("%d\n", tmp.dinic());if(road.dp[1]==1)road.add(road.s, 1, INF);if(road.dp[road.n]==road.maxn)road.add(road.n * 2, road.t, INF);road.add(1, road.n + 1, INF);road.add(road.n, road.n * 2, INF);printf("%d", road.dinic());return 0; } View Code

 

转载于:https://www.cnblogs.com/rentu/p/11323873.html

总结

以上是生活随笔为你收集整理的【P2766】 最长不下降子序列问题的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。