題目描述 description
給定正整數序列x1,..... , xn 。
(1)計算其最長遞增子串行的長度s。
(2)計算從給定的序列中最多可取出多少個長度為s的遞增子串行。
(3)如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長
度為s的遞增子串行。
輸入描述
input description
第1 行有1個正整數n,表示給定序列的長度。接
下來的1 行有n個正整數x1.....xn 。
輸出描述
output description
第1 行是最長遞增子串行的長度s。第2行是可取出的長度為s 的遞增子串行個數。第3行是允許在取出的序列中多次使用x1和xn時可取出的長度為s 的遞增子串行個數。
樣例輸入
sample input
43 6 2 5
樣例輸出
sample output22
3
正解:建圖+最大流
解題報告:
這道題的建圖方式比較簡單。第一問的話跑一下dp
就可以了,
nlogn
的最長不下降子串行dp(
n^2也可以),可以求出最大長度
maxl
。第二問考慮能從原序列中取出多少個長度為
maxl
的不下降序列。顯然當我們選擇了某個元素
a[i]
時,我們下乙個可以選擇的
a[j]
,則a[j]
是不小於當前元素且
f[j]+1=f[i]
,我們考慮如何建圖能達到題意要求。首先每個元素肯定只能用一次,並且只能按照上述順序選取。
建圖:每個點i
我們拆成兩個點
i.a和
i.b。對於每個
f[i]=maxl的i
我們從s
向i.a
連一條容量為
1的邊,
f[i]=1的i
我們從i.b向t
連一條容量為
1的邊。並且每個點內部
i.a向
i.b連一條容量為
1的邊。然後對於每個
i,都要從
i.b向所有滿足f[j]+1=f[i]且a[j]>=a[i]的j
中的j.a
都連一條容量為
1的邊。這樣建完圖之後,我們跑一遍最大流即可求出最多能取出多少個長度為
maxl
的不下降子串行。
考慮正確性。首先把每個點拆成兩個,內部容量為1
,則可以保證每個點最多被選一次。s向
f[i]=maxl
的點連邊,可以保證我們取出的起點一定是有解而且正確的。
f[i]=1
同理。如此以來,我們就能得出第二問的答案。
第三問的話實際上就是在第二問的基礎上加以改進。因為第乙個元素和最後乙個元素可以取多個,那麼我們只需要去掉對於這兩個元素的個數約束就可以了。所以s向1
、n的邊,1、n
向t的邊,內部的邊,全部把容量改為無窮大就可以了。其餘的和第二問沒有區別。
1//it is made by jump~
2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include
13#ifdef win32
14#define ot "%i64d"
15#else
16#define ot "%lld"
17#endif
18using
namespace
std;
19 typedef long
long
ll;20
const
int maxn = 520;21
const
int maxm = 500011;22
const
int inf = (1
<<30
);23
intn,a[maxn],f[maxn];
24int
b[maxn],maxl;
25int
s,t,ecnt,ans;
26int first[maxn*2],deep[maxn*2
];27 queueq;
28struct
edgee[maxm];
3132 inline int
getint()
3341
42 inline void link(int x,int y,int
z)46
47 inline int find(int
x)54
if(ji==-1) return0;
55return
ji;56}57
58 inline void build()67}
68}6970 inline bool
bfs()80}
81if(!deep[t]) return
false;82
return
true;83
}8485 inline int maxflow(int x,int
remain)else deep[v]=-1
; 97}98
}99return
flow;
100}
101102 inline void
build_new()
111else
116for(int j=i+1;j<=n;j++)
119}
120}
121122 inline void
work()
130 printf("
%d\n
",maxl);
131132
build();
133while(bfs()) ans+=maxflow(s,inf);
134if(ans==0) ans=n;
135 printf("
%d\n
",ans);
136137 ans=0
;138
build_new();
139while(bfs()) ans+=maxflow(s,inf);
140if(ans==0) ans=n;
141 printf("
%d\n
",ans);
142}
143144
intmain()
145149
codevs1906 最長遞增子串行問題 最大流
給定正整數序列x1,xn 1 計算其最長遞增子串行的長度s。2 計算從給定的序列中最多可取出多少個長度為s的遞增子串行。3 如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長 度為s的遞增子串行。第1 行有1個正整數n,表示給定序列的長度。接 下來的1 行有n個正整數x1 x...
最長遞增子串行
這是微軟實習生筆試遇到的,題意 求乙個陣列中最長遞增子串行的長度。要求選擇該題最好演算法的時間複雜度和空間複雜度。答案 時間複雜度o nlgn 空間複雜度o n 這題明顯用動態規劃來解。假設在目標陣列array 的前i個元素中,以array i 元素為最大元素的遞增子串行的長度是lis i 那麼 遞...
最長遞增子串行
最長遞增子串行又叫做最長上公升子串行 子串行,正如lcs一樣,元素不一定要求連續。本節討論實現三種常見方法,主要是練手。題 求乙個一維陣列arr i 中的最長遞增子串行的長度,如在序列1,1,2,3,4,5,6,7中,最長遞增子串行長度為4,可以是1,2,4,6,也可以是 1,2,4,6。方法一 d...