Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1149 Accepted Submission(s): 416
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).
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.
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题意:给出一串序列,求最长上升子序列和最长上升子序列的个数,要求每个数只出现一次。思路:n^2dp求出第一个解,这时就标记了以每一个数为最后一个数的上升子序列的最大长度。因为要求每个数都只出现一次,所以相当于求最多的不相交路线,可用最大流解出。将每个点拆为i和i+1,连i到i+1的边,容量为1,然后源点到每个标记长度为1的边连一条边,容量为1,标记长度为最大长度的点到汇点连一条边,长度也为1。最后对于每个点,排在它后面的且标记长度比它大1的点之间连容量为1的边。AC代码:#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <map> #include <cmath> #include <cstdlib> #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) #define ll __int64 #define eps 1e-6 using namespace std; const int INF = 1000000000; const int maxn = 1005; struct Edge { int u, v, cap, flow, next; } et[maxn*maxn]; int pre[maxn], cur[maxn], dis[maxn],cnt[maxn], low[maxn], eh[maxn]; int a[maxn], dp[maxn]; int n, s, t, num; void init() { memset(eh, -1, sizeof(eh)); num = 0; } void add(int u, int v, int cap, int flow) { Edge e = {u, v, cap, flow, eh[u]}; et[num] = e; eh[u] = num++; } void addedge(int u, int v, int cap) { add(u, v, cap, 0); add(v, u, 0, 0); } int isap(int s, int t, int nv) { int u, v, now, flow = 0; memset(cnt, 0, sizeof(cnt)); memset(low, 0, sizeof(low)); memset(dis, 0, sizeof(dis)); for(u = 0; u <= nv; u++) cur[u] = eh[u]; low[s] =INF, cnt[0] = nv, u = s; while(dis[s] < nv) { for(now = cur[u]; now != -1; now = et[now].next) if(et[now].cap - et[now].flow && dis[u] == dis[v = et[now].v] + 1) break; if(now != -1) { cur[u] = pre[v] = now; low[v] = min(et[now].cap - et[now].flow, low[u]); u = v; if(u == t) { for(; u != s; u = et[pre[u]].u) { et[pre[u]].flow += low[t]; et[pre[u]^1].flow -= low[t]; } flow += low[t]; low[s] = INF; } } else { if(--cnt[dis[u]] == 0) break; dis[u] = nv, cur[u] = eh[u]; for(now = eh[u]; now != -1; now = et[now].next) if(et[now].cap - et[now].flow && dis[u] > dis[et[now].v] + 1) dis[u] = dis[et[now].v] + 1; cnt[dis[u]]++; if(u != s) u = et[pre[u]].u; } } return flow; } int main() { while(~scanf("%d", &n)) { init(); s = 0; t = 2 * n + 1; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= n; i++) dp[i] = 1; for(int i = 2; i <= n; i++) for(int j = 1; j < i; j++) if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); //for(int i = 1; i <= n; i++) cout<<dp[i]<<endl; int ans = 0; for(int i = 1; i <= n; i++) if(dp[i] > ans) ans = dp[i]; for(int i = 1; i <=n; i++) { addedge(i, i + n, 1); if(dp[i] == 1) addedge(s, i, 1); if(dp[i] == ans) addedge(i, t, 1); for(int j = i + 1; j <=n; j++) if(dp[j] == dp[i] + 1) addedge(i + n, j, 1); } printf("%d\n%d\n", ans, isap(s, t, t+1)); } return 0; }