codevs1906 最長遞增子串行問題

2022-05-08 07:45:08 字數 3439 閱讀 7880

題目描述 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...