Problem Description


There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequence of X 
as x[i1], x[i2],...,x[ik], which satisfies follow conditions:
1) x[i1] < x[i2],...,<x[ik];
2) 1<=i1 < i2,...,<ik<=n

As an excellent program designer, you must know how to find the maximum length of the 
increasing sequense, which is defined as s. Now, the next question is how many increasing 
subsequence with s-length can you find out from the sequence X.

For example, in one case, if s = 3, and you can find out 2 such subsequence A and B from X.
1) A = a1, a2, a3. B = b1, b2, b3.
2)  Each ai or bj(i,j = 1,2,3) can only be chose once at most.

Now, the question is:
1) Find the maximum length of increasing subsequence of X(i.e. s).
2) Find the number of increasing subsequence with s-length under conditions described (i.e. num).


Input


The input file have many cases. Each case will give a integer number n.The next line will 
have n numbers.


Output


The output have two line. The first line is s and second line is num.


Sample Input


4 3 6 2 5


Sample Output


2

2


这题只要先把最长上升子序列长度算出来,然后根据dp数组建图跑网络最大流就可以了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
int m, n, a[maxn], dp[maxn], ans;

struct MaxFlow
{
#define maxe 1000010 //边数
#define maxp 10010 //点数
#define INF 0x7FFFFFFF
struct Edges
{
int to, flow;
Edges(){}
Edges(int to, int flow) :to(to), flow(flow){}
}edge[maxe];
int first[maxp], next[maxe], dis[maxp], tot, len;

void clear(){ tot = 0; memset(first, -1, sizeof(first)); }

void AddEdge(int s, int t, int flow)
{
edge[tot] = Edges(t, 0); next[tot] = first[s]; first[s] = tot++;
edge[tot] = Edges(s, flow); next[tot] = first[t]; first[t] = tot++;
}

bool bfs(int s, int t)
{
memset(dis, -1, sizeof(dis));
queue<int> p; p.push(s); dis[s] = 0;
while (!p.empty())
{
int q = p.front(); p.pop();
for (int i = first[q]; i != -1; i = next[i])
{
if (edge[i ^ 1].flow&&dis[edge[i].to] == -1)
{
p.push(edge[i].to);
dis[edge[i].to] = dis[q] + 1;
}
}
}
return dis[t] != -1;
}

int dfs(int s, int t, int low)
{
if (s == t) return low;
for (int i = first[s]; i >= 0; i = next[i])
{
if (dis[s] + 1 == dis[edge[i].to] && edge[i ^ 1].flow)
{
int x = dfs(edge[i].to, t, min(low, edge[i ^ 1].flow));
if (x)
{
edge[i].flow += x; edge[i ^ 1].flow -= x;
return x;
}
}
}
return 0;
}

int dinic(int s, int t)
{
int maxflow = 0, inc = 0;
while (bfs(s, t)) while (inc = dfs(s, t, INF)) maxflow += inc;
return maxflow;
}
}solve;

int main()
{
while (scanf("%d", &n) != EOF)
{
solve.clear(); ans = 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[j] < a[i]) ans = max(ans, dp[i] = max(dp[i], dp[j] + 1));
}
for (int i = 1; i <= n; i++)
{
if (dp[i] == 1) solve.AddEdge(0, i, 1);
if (dp[i] == ans) solve.AddEdge(i + n, n << 1 | 1, 1);
solve.AddEdge(i, i + n, 1);
for (int j = 1; j < i; j++)
if (a[j] < a[i] && dp[i] == dp[j] + 1)
{
solve.AddEdge(j + n, i, 1);
}
}
printf("%d\n%d\n", ans, solve.dinic(0, n << 1 | 1));
}
return 0;
}

这里不得不吐槽一下,之前因为ans初始值不是1的原因wa了,我还以为是哪里出错了,跑去看别人的博客,一群人在建边的时候循环都是往后走的

而且判断条件都是错的,巧妙的是即便这样判断也不会影响结果,就是多了很多条没用的边,这直接导致dinic算法tle了,也正是因为这样,让我找到了

一个神犇的代码,巧妙的优化了dinic算法。。。也算是因祸得福,涨了见识

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
int m, n, a[maxn], dp[maxn], ans;

struct MaxFlow
{
#define maxe 1000010 //边数
#define maxp 10010 //点数
#define INF 0x7FFFFFFF
struct Edges
{
int to, flow;
Edges(){}
Edges(int to, int flow) :to(to), flow(flow){}
}edge[maxe];
int first[maxp], next[maxe], dis[maxp], tot, work[maxp], n;

void clear(int x){ n = x; tot = 0; for (int i = 0; i <= n; i++) first[i] = -1; }

void AddEdge(int s, int t, int flow)
{
edge[tot] = Edges(t, 0); next[tot] = first[s]; first[s] = tot++;
edge[tot] = Edges(s, flow); next[tot] = first[t]; first[t] = tot++;
}

bool bfs(int s, int t)
{
for (int i = 0; i <= n; i++) dis[i] = -1;
queue<int> p; p.push(s); dis[s] = 0;
while (!p.empty())
{
int q = p.front(); p.pop();
for (int i = first[q]; i != -1; i = next[i])
{
if (edge[i ^ 1].flow&&dis[edge[i].to] == -1)
{
p.push(edge[i].to);
dis[edge[i].to] = dis[q] + 1;
if (dis[t] != -1) return true;
}
}
}
return dis[t] != -1;
}

int dfs(int s, int t, int low)
{
if (s == t) return low;
for (int &i = work[s]; i >= 0; i = next[i])
{
if (dis[s] + 1 == dis[edge[i].to] && edge[i ^ 1].flow)
{
int x = dfs(edge[i].to, t, min(low, edge[i ^ 1].flow));
if (x)
{
edge[i].flow += x; edge[i ^ 1].flow -= x;
return x;
}
}
}
return 0;
}

int dinic(int s, int t)
{
int maxflow = 0, inc = 0;
while (bfs(s, t))
{
for (int i = 0; i <= n; i++) work[i] = first[i];
while (inc = dfs(s, t, INF)) maxflow += inc;
}
return maxflow;
}
}solve;

int main()
{
while (scanf("%d", &n) != EOF)
{
solve.clear(n << 1 | 1); ans = 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[j] < a[i]) ans = max(ans, dp[i] = max(dp[i], dp[j] + 1));
}
for (int i = 1; i <= n; i++)
{
if (dp[i] == 1) solve.AddEdge(0, i, 1);
if (dp[i] == ans) solve.AddEdge(i + n, n << 1 | 1, 1);
solve.AddEdge(i, i + n, 1);
for (int j = i + 1; j <= n; j++)
if (dp[j] == dp[i] + 1)
{
solve.AddEdge(i + n, j, 1);
}
}
printf("%d\n%d\n", ans, solve.dinic(0, n << 1 | 1));
}
return 0;
}