题目描述
给定正整数序列x1,…,xn 。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
设计有效算法完成(1)(2)(3)提出的计算任务。
Analysis
第一问秒掉
第二问比较难想到,每个i节点按f[i]不同分了很多层,那么每次s到t的一条合法路径都是满足条件的序列。由于序列中每个点不可重复,需要拆点。边权是1所以最大流就是增广路的条数,所以最大流量就是第二问结果
第三问特殊地要求x1和xn可以重复使用,那么就取消这两个点相关边的流量限制,求网络最大流即可。
略坑爹,题目求的不是上升序列而是不下降序列
如果要求点不能重复使用,那么拆点是一种可行的方法
洛谷死活不能过,蛋疼
Code
/*
ID:wjp13241
PROG:
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define dfo(i,a,b) for(int i=a;i>=b;i--)
#define fore(i,x,e) for(int i=ls[x];i;i=e[i].next)
#define fil(x,t) memset(x,t,sizeof(x))
#define FILEIN(s) freopen(s,"r",stdin)
#define FILEOUT(s) freopen(s,"w",stdout)
#define STP system("pause")
#define min(x,y) x<y?x:y
#define max(x,y) x>y?x:y
#define MP(x,y) make_pair(x,y)
#define PuB(v,x) v.push_back(x)
#define PoB(v) v.pop_back()
#define ld long double
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define LIM 100000000
#define EPS 1e-4
#define N 10201
#define E N*20+1
#define ST 0
#define ED N-1
#define L 21
using namespace std;
struct edge{int y, w, next;}e[E];
int num[N], dis[N], cur[N], ls[N], f[N], maxE = 0;
int add(int x, int y, int w){
e[++maxE] = (edge){y, w, ls[x]};ls[x] = maxE;
e[++maxE] = (edge){x, 0, ls[y]};ls[y] = maxE;
}
int bfs(int st, int ed){
queue<int>q;
q.push(st);
fil(dis, 63);
dis[st] = 0;
while (!q.empty()){
int now = q.front();q.pop();
for (int i = ls[now]; i; i = e[i].next){
if (e[i].w > 0 && dis[now] + 1 < dis[e[i].y]){
q.push(e[i].y);
dis[e[i].y] = dis[now] + 1;
if (e[i].y == ed){
return 1;
}
}
}
}
return 0;
}
int find(int now, int ed, int mn){
if (now == ed){
return mn;
}
for (int &i = cur[now]; i; i = e[i].next){
if (e[i].w > 0 && dis[now] + 1 == dis[e[i].y]){
int d = find(e[i].y, ed, min(mn, e[i].w));
if (d > 0){
e[i].w -= d;
e[i ^ 1].w += d;
return d;
}
}
}
return 0;
}
int build(int n){
fo(i, 1, n){
fo(j, i + 1, n){
if (f[j] == f[i] + 1 && num[i] <= num[j]){
add(i + n, j, 1);
}
}
}
}
int dinic(int n){
int mxFlow = 0;
while (bfs(ST, ED)){
fo(i, 1, n + n){
cur[i] = ls[i];
}
cur[ST] = ls[ST];
cur[ED] = ls[ED];
mxFlow += find(ST, ED, INF);
}
return mxFlow;
}
int main(){
ios::sync_with_stdio(false);
int n;
cin>> n;
fo(i, 1, n)
cin>> num[i];
int ans = 0;
fo(i, 1, n){
f[i] = 1;
fo(j, 1, i-1){
if (num[j] <= num[i]){
f[i] = max(f[i], f[j] + 1);
}
ans = max(ans, f[i]);
}
}
cout<< ans<< endl;
fo(i, 1, n){
if (f[i] == 1){
add(ST, i, 1);
}
if (f[i] == ans){
add(i + n, ED, 1);
}
add(i, i+n, 1);
}
build(n);
int mxFlow = dinic(n);
cout<< mxFlow <<endl;
fil(ls, 0);
maxE = 0;
fo(i, 1, n){
int v = (i == 1 || i == n)? INF: 1;
if (f[i] == 1){
add(ST, i, v);
}
if (f[i] == ans){
add(i + n, ED, v);
}
add(i, i+n, v);
}
build(n);
mxFlow = dinic(n);
cout<< mxFlow <<endl;
return 0;
}