HDU 3998 Sequence (longest incrementing sub-Sequence + largest stream SAP, split point method) Classic, hdu3998
SequenceTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission (s): 1666 Accepted Submission (s): 614
Problem DescriptionThere 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
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 ).
InputThe input file have into cases. Each case will give a integer number n. The next line will
Have n numbers.
OutputThe output have two line. The first line is s and second line is num.
Sample Input
43 6 2 5
Sample Output
22
Source2011 Multi-University Training Contest 16-Host by TJU has two solutions:
Fang Yi: dp + largest stream (my method)
Method 2: Train of Thought: You can use n * log (n) to find the longest ascending subsequence, delete the numbers in the original array, and then find the longest ascending subsequence (if the length is reduced, ).
A sequence X (x [1], x [2],... x [n]) is given. The number is n. Calculates the length of the longest incrementing subsequence and the number of longest incrementing subsequences. Requirements: 1): x [i1] <x [i2],..., <x [ik]; (1 <= i1 <i2 ,..., <ik <= n) 2): Each number can be used only once.
Solution: for the first question: the length of the longest incrementing sub-sequence ans is very good. Now, for the second question, we first write down the position (length) of each number in the longest ascending subsequence ). Let's first make a hypothesis: if a number of num is at the 2nd position of the record, and num is the minimum value, we can find the longest ascending subsequence with the length of ans, then we can add a number (number of 1st positions) to this sequence. At this time, the maximum length of the ascending subsequence is ans + 1, because ans <ans + 1, therefore, it is in conflict with the longest incremental sub-sequence length ans. Therefore, this assumption is not true.
Conclusion: The starting Number of the longest ascending subsequence must start with the number in the first position. This is the most important reason why the largest stream is used to solve the problem.
Graph creation: (1) First, each vertex is regarded as a vertex, and then each vertex I is split into two vertices to create an edge: I --> (I + n) the edge is 1 (after the split, I points cannot be entered, and I + n points cannot be entered, except self-contained ). (2) create an edge capacity of 1: s --> I for each vertex I at the Source Vertex s = 0 and 1st. (3) create an edge with t = 2 * n + 1 for each vertex and sink point in each ans position. The capacity is 1 (I + n) --> t. (4) For The len Length Point u and the len + 1 Length point v, the size of an edge is 1. Requirements: 1) and 2 ).
# Include <stdio. h> # include <string. h> # include <queue> # include <vector> # include <algorithm> using namespace std; # define captype intconst int MAXN = 100010; // total number of points const int MAXM = 400010; // total number of edges const int INF = 1 <30; struct EDG {int to, next; captype cap, flow ;} edg [MAXM]; int eid, head [MAXN]; int gap [MAXN]; // number of each distance (or can be considered as a height) vertex int dis [MAXN]; // int cur [MAXN], the shortest distance between each node and the End Node eNode; // cur [u] indicates that the edge of cur [u] can flow through the int pre [MAXN]; void init () {eid = 0; memset (head,-1, sizeof (head);} // three parameters with a directed edge, void addEdg (int u, int v, captype c, captype rc = 0) {edg [eid]. to = v; edg [eid]. next = head [u]; edg [eid]. cap = c; edg [eid]. flow = 0; head [u] = eid ++; edg [eid]. to = u; edg [eid]. next = head [v]; edg [eid]. cap = rc; edg [eid]. flow = 0; head [v] = eid ++;} captype maxFlow_sap (int sNode, int eNode, int n) {// n indicates the total number of points including the Source and Sink points, memset (gap, 0, sizeof (gap); mems Et (dis, 0, sizeof (dis); memcpy (cur, head, sizeof (head); pre [sNode] =-1; gap [0] = n; captype ans = 0; // maximum stream int u = sNode; while (dis [sNode] <n) {// determine whether the sNode point has a flow to the next adjacent point if (u = eNode) {// find a route captype Min = INF; int inser; for (int I = pre [u]; I! =-1; I = pre [edg [I ^ 1]. to]) // find the maximum traffic that can be increased by Min if (Min> edg [I]. cap-edg [I]. flow) {Min = edg [I]. cap-edg [I]. flow; inser = I;} for (int I = pre [u]; I! =-1; I = pre [edg [I ^ 1]. to]) {edg [I]. flow + = Min; edg [I ^ 1]. flow-= Min; // flow of the reflux edge} ans + = Min; u = edg [inser ^ 1]. to; continue;} bool flag = false; // judge whether int v can flow to adjacent points from the u point; for (int I = cur [u]; I! =-1; I = edg [I]. next) {v = edg [I]. to; if (edg [I]. cap-edg [I]. flow> 0 & dis [u] = dis [v] + 1) {flag = true; cur [u] = pre [v] = I; break ;}} if (flag) {u = v; continue;} // if no adjacent vertex of the stream is found above, the distance (or height) of the starting point u is changed) + 1 int Mind = n; for (int I = head [u]; I! =-1; I = edg [I]. next) if (edg [I]. cap-edg [I]. flow> 0 & Mind> dis [edg [I]. to]) {Mind = dis [edg [I]. to]; cur [u] = I;} gap [dis [u] --; if (gap [dis [u] = 0) return ans; // when the distance of dis [u] is absent, it is impossible to find an augmented stream path from the source point. // there is only one distance between the sink point and the current point, then, from the source point to the sink point will inevitably pass through the current point. However, if the current point fails to find the point that can flow, it will inevitably cut off dis [u] = Mind + 1; // If a adjacent vertex that can be streamed is found, the distance between the adjacent vertex is + 1. If not, the distance is n + 1 gap [dis [u] ++; if (u! = SNode) u = edg [pre [u] ^ 1]. to; // return an edge} return ans;} int binarySearch (int * dp, int num, int ans) {int l = 1, r = ans, mid; while (l <= r) {mid = (l + r)> 1; if (dp [mid]> = num) r = mid-1; else l = mid + 1;} return l;} int main () {int n, num [MAXN], dp [MAXN]; while (scanf ("% d ", & n)> 0) {for (int I = 1; I <= n; I ++) scanf ("% d", & num [I]), dp [I] = INF; int ans = 0; // The length of the longest incrementing sub-sequence vector <int> vct; vct = vector <int> (n, vector <int> (0, 0); for (int I = 1; I <= n; I ++) {int len = binarySearch (dp, num [I], ans); vct [len]. push_back (I); if (dp [len]> num [I]) dp [len] = num [I]; if (ans <len) ans = len ;} init (); int s = 0, t = 2 * n + 1; for (int I = 1; I <= n; I ++) // split the vertex, each vertex can be regarded as an edge, so the capacity is 1 addEdg (I, I + n, 1); for (int I = vct [1]. size ()-1; I> = 0; I --) addEdg (s, vct [1] [I], 1); for (int I = vct [ans]. size ()-1; I> = 0; I --) addEdg (vct [ans] [I] + n, t, 1); for (int len = 1; len <ans; len ++) for (int I = vct [len]. size ()-1; I> = 0; I --) {int u = vct [len] [I]; for (int j = vct [len + 1]. size ()-1; j> = 0; j --) {int v = vct [len + 1] [j]; if (u> v) break; // If v is in front of u, it cannot meet the following requirements: 1 <= i1 <i2 ,..., <ik <= n if (num [u]> = num [v]) continue; addEdg (u + n, v, 1) ;}} int k = maxFlow_sap (s, t, t + 1); // The maximum number of subsequences that increase progressively. It is equivalent to the number of (s --> t) paths, each side can only use printf ("% d \ n", ans, k );}}