題意:n個數,各出現兩次,當兩個相同的數相鄰時,這兩個數同時消除,上方的方塊同時下落且可繼續消除滿足條件的。每次可交換相鄰的兩個方塊,求最少交換次數使得所有數全消除
首先,對於一對相同的數中間有另一對的情況(即兩對相同的數是巢狀關係),肯定要先消除另一對
其次,對於一對相同的數中間有另一對中的乙個的情況(即兩對相同的數有交集),先消除哪個其實是一樣的(把一對換到另一對外或把另一對換到這一對裡是等價的)
那麼我們有兩種實現方式:
(1)方法一
用棧模擬我們上述過程,如果乙個元素已經出現在棧裡,找出並刪除同時進行維護,對答案的貢獻就是兩個位置中間棧的元素數,即 top-i (i為第一次出現的位置在棧中位置)
var
n,x,top,ans :longint;
vis :array[0..50010] of boolean;
z :array[0..100010] of longint;
i :longint;
procedure find(x,pos:longint);
var i,j:longint;
begin
for i:=top downto 1 do
if z[i]=x then break;
inc(ans,top-i);
for j:=i to top-1 do z[j]:=z[j+1];
dec(top);
end;
begin
read(n);
for i:=1 to 2*n do
begin
read(x);
if not vis[x] then
begin
vis[x]:=true;
inc(top); z[top]:=x;
end else find(x,i);
end;
writeln(ans);
end.
經親測
(2)方法二
依次讀入的時候,如果是第二次出現,那麼就把它和第一次出現的位置合併,那麼必須交換的次數為(second-first-1)即兩者之間的距離,證明見上分類。用樹狀陣列維護即可
var
n,x,ans :longint;
i :longint;
first :array[0..50010] of longint;
t :array[0..100010] of longint;
function lowbit(x:longint):longint;
begin
exit(x and (-x));
end;
procedure add(x,v:longint);
begin
while (x<=n*2) do
begin
inc(t[x],v);
inc(x,lowbit(x));
end;
end;
function find(x:longint):longint;
var ans:longint;
begin
ans:=0;
while (x>0) do
begin
inc(ans,t[x]);
dec(x,lowbit(x));
end;
exit(ans);
end;
begin
read(n); ans:=0;
for i:=1 to n*2 do
begin
read(x);
if first[x]=0 then
begin
first[x]:=i;
add(i,1);
end else
begin
inc(ans,find(i)-find(first[x]-1)-1);
add(first[x],-1);
end;
end;
writeln(ans);
end.
經親測
兩種方法的思路是一樣的,即對答案的貢獻為第一次位置和第二次位置之間的距離(中間的滿足條件的消除後的),只是維護的方法不一樣而已
第一種用到棧頂的距離維護,第二種用樹狀陣列維護
bzoj1246(樹狀陣列)
樹狀陣列的靈活運用,維護的是最大值,因為整個陣列就是乙個字首最大值,所以可以用實現,求乙個字首最大值,和更新pos之後的最大值。很好的運用,多回顧思考 include include include include includeusing namespace std const int n 200...
bzoj 2762 樹狀陣列
題意 給出一些形如 ax b 1 新加入乙個不等式 2 刪除乙個不等式 3 詢問當x k時滿足的不等式的個數 對於每乙個不等式,通過變形就可以得到使它成立的x的範圍 那麼就變成區間修改,單點查詢,樹狀陣列維護就好 注意 1 討論a 0 a 0 a 0的情況 2 由於k有非正數,所以要加上10 6 1...
bzoj 1935(樹狀陣列)
傳送門 題解 由於是靜態問題所以可以離線處理,所有點 詢問拆成4個 按x排序,二維可以轉成一維,相當於每次query到的就是當前已插入的點,而只有這些點能對query的返回值造成貢獻。p.s.對於x座標相同的插入 詢問,要考慮這幾個操作的先後順序 include using namespace st...