原题:
共三问:
(1)最长上升子序列长度s
(2)每个数用一遍,能够得到的最多长度为s的子序列个数
(3)同第二问,a[1]与a[n]可用多次
分析:
(1)对于第一问,直接dp。
(2)第二问,拆点后建图,根据第一问求出的LIS,如果LIS[i] = LIS[j]+1 && i < j && a[i] < a[j],则连接一条i->j容量为1的有向边,最后左一边最大流即可。
(3)第三问,同第二问建图方法,同时S->1, n->T的流量为正无穷。
code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define REP(i, l, r) for (int i = l; i >= r; i--)
#define INF 19971228
#define MAXN 1010
int n, N = -1, seq[MAXN], f[MAXN], maxs = -INF, S, T, first[MAXN], next[MAXN], dis[MAXN];
struct tlist {int x, y, f;} a[MAXN];
queue<int> q;
inline int min(int a, int b) {return a<b ? a : b;}
inline int max(int a, int b) {return a>b ? a : b;}
inline void add(int x, int y, int f) {
a[++N].x = x, a[N].y = y, a[N].f = f, next[N] = first[x], first[x] = N;
a[++N].x = y, a[N].y = x, a[N].f = 0, next[N] = first[y], first[y] = N;
}
inline bool bfs() {
while (!q.empty()) q.pop();
memset(dis, -1, sizeof(dis));
q.push(S);
dis[S] = 0;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = first[x]; ~i; i = next[i])
if (!~dis[a[i].y] && a[i].f) {
dis[a[i].y] = dis[x] + 1;
q.push(a[i].y);
}
}
return ~dis[T];
}
inline int find(int x, int low) {
if (x == T) return low;
int sum = 0, temp;
for (int i = first[x]; ~i; i = next[i])
if ((a[i].f) && (dis[a[i].y] == dis[x] + 1) && (temp = find(a[i].y, min(low-sum, a[i].f)))) {
a[i].f -= temp;
a[i^1].f += temp;
sum += temp;
}
return sum;
}
inline int dinic() {
int ans = 0, temp;
while (bfs())
while (temp = find(S, 0x7fffffff))
ans += temp;
return ans;
}
int main() {
cin >> n;
S = 0, T = 2*n+1;
memset(first, -1, sizeof(first));
memset(next, -1, sizeof(next));
rep(i, 1, n) scanf("%d", &seq[i]);
rep(i, 0, n) f[i] = 1;
REP(i, n-1, 1) {
int cur = f[i];
rep(j, i+1, n) if (seq[j] > seq[i]) f[i] = max(f[i], cur + f[j]);
}
rep(i, 1, n) maxs = max(maxs, f[i]);
cout << maxs << endl;
rep(i, 1, n) {
if (f[i] == maxs) add(S, i, 1);
if (f[i] == 1) add(n+i, T, 1);
}
rep(i, 1, n) add(i, n+i, 1);
rep(i, 1, n)
rep(j, i+1, n)
if ((seq[j] > seq[i]) && (f[i] == f[j]+1))
add(n+i, j, 1);
cout << dinic() << endl;
N = -1;
memset(first, -1, sizeof(first));
memset(next, -1, sizeof(next));
if (f[1] == maxs) add(S, 1, INF);
if (f[1] == 1) add(n+1, T, 1);
rep(i, 2, n-1) {
if (f[i] == maxs) add(S, i, 1);
if (f[i] == 1) add(n+i, T, 1);
}
if (f[n] == maxs) add(S, n, 1);
if (f[n] == 1) add(n+n, T, INF);
add(1, n+1, INF);
rep(i, 2, n-1) add(i, n+i, 1);
add(n, n+n, INF);
rep(i, 1, n)
rep(j, i+1, n)
if ((seq[j] > seq[i]) && (f[i] == f[j]+1))
add(n+i, j, 1);
cout << dinic() << endl;
return 0;
}