給出 k 和 n 個數,構造乙個序列使得 d[i]>=d[i/k] ,並且字典序最大。
聽說,當年省選的時候,這道題擋住了大批的高手,看上去十分簡單,實際上那道彎段時間內是轉不過來的。
首先,乙個套路是,將這個序列的關係抽象成一棵樹,i的父親是floor(i/k),我們要要求子樹內部的點的權值都比父親大。
我們觀察子任務的特殊限制,di不一樣?
我們想,把原序列從大到小排序,在樹上dfs給點賦值,在給乙個點賦值時,要在序列上預留出siz[這棵子樹]的位置,用來給子樹內部的點賦值(排序就是為了方便在序列上預留位置)。
但是,如果有重複的元素就辦不了了,比如n=4, k=2 序列是1,1,1,2.
排好應該是1 1 2 1,但是我們上面的方法會排成1 1 1 2
為什麼呢?
我們從大到小排序,應該得到2 1 1 1.我們遞迴,首先是樹根節點,需要預留4個位置,所以肯定要選最後乙個(1),然後遞迴到第乙個子樹(序號為2),size為2,需要在這個子樹留兩個位置,所以我們把第二個1給了序號2這個位置,然後那個2就給了它的兒子(序號4)但是實際上,我們可以給它留乙個1,把這個4給位置3.
我這麼分析會很亂,但是我們於情於理考慮一下,我們解決完了位置2,若想字典序最大,我們應該先最大化3這個位置。
所以我們應該在給序號2找到最大值之後,應該為他的子樹預留一些值,使這些值在合法的基礎上盡可能小。
所以我們應該排序後,建立乙個序列c,c[i]的值代表排好序的序列上,i及i左邊的所有值還剩下多少個可以選的。
(序列c一開始肯定是1,2,3,4,5……)
然後我們每次為乙個點賦值,應該找到最靠左的乙個位置i,使所有j>=i滿足c[j]>=siz[這個點的子樹]。
並且選完之後,要找到這個位置往右最右邊和他值相等的那個位置(前提是沒有被用過的)。
然後,用區間減法計算貢獻,之後接著處理這個點的兄弟節點,沒有了兄弟節點之後在進入某個點的子節點。
進入乙個子節點時,要將之前預留的位置(區間減去的數值)加回來,但是已經分配出去的(父親的)權值就不要加回來了。
所以是siz-1
**:
1 #include2貪心+線段樹#define db double
3using
namespace
std;
4const
int n=500005,inf=1e9;
5struct
segtreet[n*4];int
a[n],b[n],ans[n],m,rt;
8 db k;int n,siz[n],fa[n],cnt[n],o=0;9
bool cmp(int u,int v)
10void pushup(int
cur) void pushdown(int
cur) void build(int x,int l,int
r) int mid=l+r>>1
;24 t[x].ls=o++;t[x].rs=o++;
25 build(t[x].ls,l,mid);build(t[x].rs,mid+1
,r);
26 pushup(x);return
;27 } void update(int x,int l,int r,int
c)30 pushdown(x);int mid=t[x].l+t[x].r>>1;31
if(l<=mid) update(t[x].ls,l,r,c);
32if(mid
33 pushup(x);return
;34 } int query(int x,int
p) int
main() for(int i=1;i<=n;i++)
57 printf("
%d "
,a[ans[i]]);
58return0;
59 }
九省聯考2018 IIIDX 貪心 線段樹
題面 題解 首先有乙個比較明顯的50分貪心 先把d排好序,然後按從小到大的順序貪心的給每個點選值,同等條件下優先編號大的,於是越小的值會越趨近於放在編號越大的上面。但是這樣在數字重複的情況下是不對的,比如下面這組資料 4 3.0 1 1 2 2 貪心會得到1 1 2 2 而正確答案是1 2 2 1....
九省聯考2018 IIIDX 貪心
題目背景 osu聽過沒?那是konano最喜歡的一款 遊戲,而他的夢想就是有一天自己也能做個獨特酷炫的 遊戲。現在 他在世界知名遊戲公司konmai內工作,離他的夢想也越來越近了。這款 遊戲內一般都包含了許多歌曲,歌曲 越多,玩家越不易玩膩。同時,為了使玩家在遊戲上氪更多的金錢花更多的時間,遊戲一開...
2472 九省聯考 2018 IIIDX
一眼思路的題 就是比較難寫.考慮乙個點必須小於其 i dk id k 那麼容易想出乙個樹形結構,每個點都大於其父親.那麼對於乙個點,那麼他能選取的最大值就是當前能選的所有點中的n size id n s ize id 這個點的值。然後留夠其兒子的位置即可。最後如果有相同的點,容易想到把當前點放在權值...