bzoj 3173 最長上公升子串行

2021-06-23 03:18:53 字數 2962 閱讀 1126

給定乙個序列,初始為空。現在我們將1到n的數字插入到序列中,每次將乙個數字插入到乙個特定的位置。每插入乙個數字,我們都想知道此時最長上公升子串行長度是多少?

第一行乙個整數n,表示我們要將1到n插入序列中,接下是n個數字,第k個數字xk,表示我們將k插入到位置xk(0<=xk<=k-1,1<=k<=n)

n行,第i行表示i插入xi位置後序列的最長上公升子串行的長度是多少。

3

0 0 2

112

提示

x0等於0 ,我們將1插入到位置0得到序列

x1等於0 ,我們將1插入到位置0得到序列

x2等於2 ,我們將1插入到位置0得到序列

資料範圍

30%„的資料 n<=1000

100%的資料 n<=100000

analysis

因為數字是從小到大插入的,所以我們可以構造出最終序列,然後o(nlogn)求最長上公升子串行。

關鍵是構造出最終序列。

2b青年:我會平衡樹!(我連2b都不如

平衡樹模擬插入,求出最終序列,雖然可以過,但是**量和時間不盡人意。

下面來講一下文藝的做法吧...

我們發現,將整個序列反過來做,如果當前數插入的位置定了,將不會再受到影響。

而這樣子就可以用樹狀陣列維護,首先將所有的位置都設為一,每次插入乙個數,相當於找到最前面的一段區間,它們的和=當前數插入的位置(設為l[1,i]),則這個插入的數的位置就是i。插入之後,將i這個位置置為零(用過了)。

可以通過二分來找到這個i,更好的方法是通過二進位制(剛學)。

看下面的**:

function get(k:longint):longint;

var ans,cnt,i:longint;

begin

ans:=0; cnt:=0;

for i:=20 downto 0 do begin

ans:=ans+1 shl i;

if (ans>=n) or (cnt+c[ans]>=k) then ans:=ans-1 shl i

else cnt:=cnt+c[ans];

end;

exit(ans+1);

end;

這是用樹狀陣列的定義來加速處理的方法,i從20開始取是因為資料範圍<=100000(理解不了可以看一下樹狀陣列的定義)。

接下來我們就可以還可以再用樹狀陣列維護乙個區間最大值,當然直接套o(nlogn)的最長上公升子串行的傳統做法也可以,不過樹狀陣列比較方便。

上**:(沒看懂

var

i,j,k,n,tmp:longint;

c,cnt,pos,ans,fa:array[0..100000] of longint;

function getfa(t:longint):longint;

begin

if fa[t]=t then exit(t);

fa[t]:=getfa(fa[t]);

getfa:=fa[t];

end;

function lowbit(x:longint):longint;

begin

exit(x and (-x));

end;

function max(a,b:longint):longint;

begin

if a>b then exit(a) else exit(b);

end;

procedure change(x,delta:longint);

begin

while x0 do begin

getmax:=max(getmax,c[x]);

x:=x-lowbit(x);

end;

end;

function get(k:longint):longint;

var ans,cnt,i:longint;

begin

ans:=0; cnt:=0;

for i:=20 downto 0 do begin

ans:=ans+1 shl i;

if (ans>=n) or (cnt+c[ans]>=k) then ans:=ans-1 shl i

else cnt:=cnt+c[ans];

end;

exit(ans+1);

end;

begin

readln(n);

for i:=1 to n do begin read(pos[i]); inc(pos[i]); inc(c[i]); if i+lowbit(i)<=n then c[i+lowbit(i)]:=c[i+lowbit(i)]+c[i]; end;

for i:=n downto 1 do begin

j:=get(pos[i]);

cnt[i]:=j;

while j

dec(c[j]);

j:=j+lowbit(j);

end;

end;

for i:=1 to n do c[i]:=0;

for i:=1 to n do begin

tmp:=getmax(cnt[i]-1)+1;

ans[i]:=max(ans[i-1],tmp);

change(cnt[i],tmp);

end;

for i:=1 to n do writeln(ans[i]);

end.

bzoj3173 最長上公升子串行

portal bzoj3173 solution 感覺自己需要智力 qwq 首先題目給的這個序列肯定是乙個 1 n 的排列,並且插入的順序是從小到大 仔細思考一下會發現如果知道了最終的序列,問題就比較好解決了,這裡提供一種用線段樹的做法 如果知道了最終的序列,記數字 i 在該序列中的位置為 loc ...

最長上公升子串行

問題描述 乙個數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列 a1,a2,an 我們可以得到一些上公升的子串行 ai1,ai2,aik 這裡1 i1 i2 ik n。比如,對於序列 1,7,3,5,9,4,8 有它的一些上公升子串行,如 1,7 3,4,8 等等...

最長上公升子串行

最長上公升子串行問題是各類資訊學競賽中的常見題型,也常常用來做介紹動態規劃演算法的引例,筆者接下來將會對poj上出現過的這類題目做乙個總結,並介紹解決lis問題的兩個常用 演算法 n 2 和 nlogn 問題描述 給出乙個序列a1,a2,a3,a4,a5,a6,a7.an,求它的乙個子串行 設為s1...