LOJ6005 「网络流 24 题 - 6」 最长递增子序列 坠大流
2017-12-07 10:55
281 查看
大家都很强, 可与之共勉 。
题意:给定正整数序列 x1~xn ,以下递增子序列均为非严格递增。
计算其最长递增子序列的长度s。
计算从给定的序列中最多可取出多少个长度为s的递增子序列。
如果允许在取出的序列中多次使用x1和xn ,则从给定序列中最多可取出多少个长度为s的递增子序列。
题解:
我忘了O(nlogn)的最长不递减子序列怎么写
第一问即是裸题,直接单调栈优化的最长上升子序列求解就可以了。
第二问用网络流,考虑如何建边才能使得每一条路径都是长度为s的子序列且每个数只能使用一次。
我们已经预处理出了f[i]数组表示以第i个结尾的最长不递减子序列的长度。设第一问的答案为k。
然后拆点,每个点a,拆为(a1,a2),然后a1向a2连一条容量为1的弧,保证每个点一定只使用一次。
建立源点S,汇点T。
其中对于f[u]=1的点,S向u1连一条容量为1的弧,对于f[v]=k的点,v2向T连一条容量为1的弧。
然后对于i>j且a[j]≤a[i],我们连一条j2→i1,流量为1的边。
然后跑最大流就好了,一定保证从S到T的路径长度为k,最大流就是方案数。
第三问在第二问的基础上完成,我们发现要求的只是a1,an可以任意多次使用,那么把与之相关的四条边容量改为+∞。即是S→11,11→12,n1→n2,n2→T。
就保证了正确性。注意一些细节
# include <bits/stdc++.h> # define N 5005 class Network { private : struct edge { int to, w, nxt ; edge ( ) { } edge ( int to, int w, int nxt ) : to ( to ), w ( w ), nxt ( nxt ) { } } g [60010 << 1] ; int head , cur , ecnt ; int S, T , dep ; inline int dfs ( int u, int a ) { if ( u == T || ! a ) return a ; int flow = 0, v, f ; for ( int& i = cur [u] ; i ; i = g [i].nxt ) { v = g [i].to ; if ( dep [v] == dep [u] + 1 ) { f = dfs ( v, std :: min ( g [i].w, a - flow ) ) ; g [i].w -= f, g [i ^ 1].w += f ; flow += f ; if ( a == flow ) return a ; } } if ( ! flow ) dep [u] = -1 ; return flow ; } inline bool bfs ( int S, int T ) { static std :: queue < int > q ; memset ( dep, 0, sizeof ( int ) * ( T + 1 ) ) ; dep [S] = 1 ; q.push ( S ) ; while ( ! q.empty ( ) ) { int u = q.front ( ) ; q.pop ( ) ; for ( int i = head [u] ; i ; i = g [i].nxt ) { int& v = g [i].to ; if ( g [i].w && ! dep [v] ) { dep [v] = dep [u] + 1 ; q.push ( v ) ; } } } return dep [T] ; } public : Network ( ) { ecnt = 1 ; } inline void add_edge ( int u, int v, int w ) { g [++ ecnt] = edge ( v, w, head [u] ) ; head [u] = ecnt ; g [++ ecnt] = edge ( u, 0, head [v] ) ; head [v] = ecnt ; } inline void clear ( ) { ecnt = 1 ; memset ( head, 0, sizeof head ) ; } inline int dinic ( int S, int T ) { this -> S = S, this -> T = T ; int rt = 0 ; while ( bfs ( S, T ) ) { memcpy ( cur, head, sizeof ( int ) * ( T + 1 ) ) ; rt += dfs ( S, 0x3f3f3f3f ) ; } return rt ; } } Lazer ; int f ; inline int Lis ( int* s, int n ) { if ( n == 0 ) return 0 ; int* src = new int [( const int ) n + 1] ; int len ( 1 ) ; src [1] = s [1] ; f [1] = 1 ; for ( int i = 2 ; i <= n ; ++ i ) { src [f [i] = ( s [i] >= src [len] ) ? ( ++ len ) : ( std :: upper_bound ( src + 1, src + 1 + len, s [i] ) - src )] = s [i] ; } return len ; } int a ; int main ( ) { int n ; scanf ( "%d", & n ) ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d", a + i ) ; } int ans = Lis ( a, n ) ; printf ( "%d\n", ans ) ; const int S = n * 2 + 1, T = n * 2 + 2 ; for ( int i = 1 ; i <= n ; ++ i ) { if ( f [i] == ans ) { Lazer.add_edge ( i + n, T, 1 ) ; } // no else if ( f [i] == 1 ) { Lazer.add_edge ( S, i, 1 ) ; } Lazer.add_edge ( i, i + n, 1 ) ; } for ( int i = 1 ; i <= n ; ++ i ) for ( int j = 1 ; j < i ; ++ j ) if ( f [i] == f [j] + 1 && a [i] >= a [j] ) { Lazer.add_edge ( j + n, i, 1 ) ; } printf ( "%d\n", Lazer.dinic ( S, T ) ) ; Lazer.clear ( ) ; for ( int i = 1 ; i <= n ; ++ i ) { if ( f [i] == ans ) { Lazer.add_edge ( i + n, T, i == n ? 0x3f3f3f3f : 1 ) ; } if ( f [i] == 1 ) { // no else Lazer.add_edge ( S, i, i == 1 ? 0x3f3f3f3f : 1 ) ; } Lazer.add_edge ( i, i + n, i == 1 || i == n ? 0x3f3f3f3f : 1 ) ; } for ( int i = 1 ; i <= n ; ++ i ) for ( int j = 1 ; j < i ; ++ j ) if ( f [i] == f [j] + 1 && a [i] >= a [j] ) { Lazer.add_edge ( j + n, i, 1 ) ; } printf ( "%d\n", Lazer.dinic ( S, T ) ) ; return 0 ; }
相关文章推荐
- 【线性规划与网络流24题 6】最长递增子序列
- Cogs 731. [网络流24题] 最长递增子序列(最大流)
- [网络流24题]最长递增子序列问题 最大流
- 网络流24题 最长递增子序列问题
- 最长递增子序列问题[网络流24题之6]
- COGS731 [网络流24题] 最长递增子序列(最大流)
- 【网络流24题】最长递增子序列问题
- [网络流24题] 最长递增子序列问题 最大流/
- [网络流24题]最长递增子序列问题
- [网络流24题] 06 最长递增子序列(最多不相交路径,最大流)
- [网络流24题] 最长递增子序列
- [网络流24题]最长递增子序列问题
- code vs [网络流24题] 最长递增子序列问题
- 网络流24题之六 最长递增子序列
- 【codevs1906】[网络流24题]最长递增子序列问题
- [网络流24题] 最长递增子序列 (最多不相交路径---网络最大流)
- 网络流24题之T6 最长递增子序列问题
- kyeremal-网络流24题T6-最长递增子序列问题
- 网络流24题6. 最长递增子序列问题
- 网络流24题:最长递增子序列问题