题目描述
«问题描述:
给定正整数序列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
说明/提示
n≤500
【解题思路】
【代码】

#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;
}
