题意:
给定正整数序列x1,...,xn 。
(1)计算其最长不下降子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。
«编程任务:
设计有效算法完成(1)(2)(3)提出的计算任务。
思路:第一问直接n方dp,第二、三问就要建图网络流了。
建图方案:
为了让每个点只用次,把每个点拆成两部分,入点和出点,入点和出点连一条容量为1的边。源点连到dp[i]=1的入点上,容量为1。dp[i]=max的点连到汇点上,容量为1,这样跑dinic就是第二问的答案。第三问就是给s~1还有1~n+1这两条边的容量置为INF,若点n的dp[n]=max的话,把n~t和n~n+n这两条边的容量也置为INF,跑dinic就是第三问的答案。
这个题坑点有点多,wa了好几次。
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N = 2e5 + 10;
int n, m, s, t, h[N], cnt, dep[N], cur[N], a[N], dp[N];
struct node {
int v, w, nt;
} no[N];
void add(int u, int v, int w) {
no[cnt] = node{v, w, h[u]};
h[u] = cnt++;
no[cnt] = node{u, 0, h[v]};
h[v] = cnt++;
}
int bfs() {
queue<int> q;
memset(dep, 0, sizeof dep);
dep[s] = 1;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = h[u]; ~i; i = no[i].nt) {
int v = no[i].v;
if(!dep[v] && no[i].w > 0) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[t] > 0;
}
int dfs(int u, int flow) {
if(u == t)
return flow;
for(int &i = cur[u]; ~i; i = no[i].nt) {
int v = no[i].v;
if(dep[v] == dep[u] + 1 && no[i].w) {
int res = dfs(v, min(flow, no[i].w));
if(res > 0) {
no[i].w -= res;
no[i ^ 1].w += res;
return res;
}
}
}
return 0;
}
int dinic() {
int res = 0;
while(bfs()) {
for(int i = 0; i <= t; i++)//这必须是t,不然死循环
cur[i] = h[i];
while(int d = dfs(s, INF))
res += d;
}
return res;
}
int main() {
memset(h, -1, sizeof h);
scanf("%d", &n);
int mx = 1;
for(int i = 1; i <= n; i++)
scanf("%d", a + i), dp[i] = 1;
for(int i = 1; i <= n; i++)
for(int j = 1; j < i; j++)
if(a[i] >= a[j])
dp[i] = max(dp[i], dp[j] + 1), mx = max(mx, dp[i]);
t = n * 2 + 1;
for(int i = 1; i <= n; i++) {
add(i, i + n, 1);
if(dp[i] == 1)
add(s, i, 1);
if(dp[i] == mx)
add(i + n, t, 1);
}
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
if(a[j] >= a[i] && dp[j] == dp[i] + 1)
add(i + n, j, 1);
int ans = dinic();
add(s, 1, INF), add(1, n + 1, INF);
if(dp[n] == mx)
add(n, n + n, INF), add(n + n, t, INF);
int s3 = ans + dinic();
printf("%d\n%d\n%d\n", mx, ans, s3);
return 0;
}