思路一:
這道題目經過簡化後,我發現這道題目其實是想要我們去模擬乙個過程,即不斷維護乙個嚴格遞增的序列,如果遍歷到了第i個數,則將這個數字放到第a[i]+1(下標從1開始)的位置,然後讓原來的a[i] + 1 - i位置的數往後移動乙個單位,然後我就想到者相當與就是乙個區間增加的過程,最後用樹狀陣列去維護差分陣列寫出來下面的**:
#include
#include
using
namespace std;
const
int maxn =
1e5+5;
int l, r, n;
int a[maxn]
, b[maxn]
, c[maxn]
;inline
intlowbit
(int x)
inline
void
change
(int idx,
int x)
inline
intquery
(int x)
return res;
}int
main
(void
)for
(int i =
1; i <= n; i ++
)change
(i, b[i]);
for(
int i =
1; i <= n; i ++)}
for(
int i =
1; i <= n; i ++
) a[i]
=query
(i);
for(
int i =
1; i <= n; i ++)if
(i == n)
printf
("%d"
, a[i]+1
);else
printf
("%d\n"
, a[i]+1
);return0;
}
然而這份**是有問題的,因為在不斷去交換的過程中,我的這份**僅僅只是使用了乙個差分,沒有考慮到數字之間的交換,即忽略了這種情況,如果第j位的數需要到第j位上,然後第k位置的數導致了從j - 2 到 j + 2的數字需要往後移動乙個位置,這時候,其實我們移動的依然是原來在第j位上的數,但是實際上,原來第j位的數應該到第i位上,所以就錯了,這時候如果我們強行去更換位置,時間複雜度就變成了o(n^2)了,所以,這個思路被pass.
然後,我發現從前往後找不管怎樣都逃不過位置變換的問題,然後我想從後往前找是不是會更好;然後我發現乙個現象,最後乙個位置的數的位置的直接確定的,即後往前找,只需要不斷地去掉乙個數字,然後再不斷地去找數字就可以了;就相當於,我們每次需要從剩下地數中去尋找第a[i] + 1小地數,然後再將剩下的數字去掉找到的這個數,然後我直接想到用主席樹去寫,然後我想樹狀陣列是不是也是直接用陣列去記錄每個數字的個數就可以了,但是由於樹狀陣列只能找到從1 - x範圍內有多少個數字,由於有著單調性,所以再使用乙個二分,最後就將這道題目寫了出來,時間複雜度是:o(n * (logn)^2),不會超時:
貼上**乙份:
#include
#include
using
namespace std;
const
int maxn =
1e5+5;
int n;
int a[maxn]
, b[maxn]
;inline
intlowbit
(int x)
inline
void
add(
int idx,
int x)
inline
intquery
(int x)
return res;
}inline
intfind
(int x)
return l;
}int
main
(void
)for
(int i =
1; i <= n; i ++)if
(i == n)
printf
("%d"
, a[i]);
else
printf
("%d\n"
, a[i]);
return0;
}
E Minimum Array 樹狀陣列 二分
其實貪 心還是比 較顯 然其實貪心還是比較顯然 其實貪心還是 比較顯然對於 乙個ai 我們最 好找到b j n ai 對於乙個a i,我們最好找到b j n a i 對於乙個ai 我們 最好找到 bj n ai 這樣 對n求餘 後就是0 最 優這樣對n求餘後就是0,最優 這樣對n求餘 後就是0 最優...
D Multiset(樹狀陣列 二分)
二分 樹狀陣列做法 這個時候我們的 tree 陣列就相當與乙個桶,每個桶裡統計的是值為其下標的個數,通過樹狀陣列的字首和性質,我們可以通過二分輕鬆的鎖定第 k 項的位置,然後進行刪除操作,具體的操作細節看 實現。權值線段樹做法 線段相較而言,常數大一些,維護的基本思路還是更樹狀陣列是一樣的。當我樹狀...
求逆序 二分 樹狀陣列
include includeusing namespace std int a 100001 n,temp 100001 long long ct 0 void merg int first,int last else 把剩下的按序放進陣列。while i mid while j n for in...