首先我們忽略 \(c\) 的限制,如果只考慮 \(d\) 的話,不難發現以第 \(i\) 個人結尾分組,左端點是一段連續的區間 \([lft_i,i)\)。 可以用 st 表預處理區間最小值然後雙指標掃一遍求出 \(lft\)。
加入了 \(c\) 的限制之後,此時和每乙個點能轉移過來的位置就不是連續的區間了。考慮對於當前區間內 \(c\) 的最大值分治,也就是建出笛卡爾樹然後按照深度優先遍歷進行轉移。
設區間 \([l,r]\),最大值所在位置為 \(mid\),先遞迴處理 \([l,mid)\),然後求 \([l,mid)\) 對 \([mid,r]\) 的貢獻。考慮三種情況:
\(lft_i\leq l\) 且 \(i\geq mid+c_\)
這一段顯然可以被 \([l,mid)\) 全部貢獻到,直接線段樹區間查詢,再區間賦值即可。
\(l因為每乙個點指揮在這樣的情況一次,所以直接暴力線段樹區間詢問即可。
到葉子節點之後在 \(f\) 和線段樹上取一下最優即可。
時間複雜度 \(o(n\log n)\)。
#include #define mp make_pair
using namespace std;
const int n=1000010,lg=20,mod=1e9+7;
int n,c[n],d[n],lft[n],lg[n],st[n][lg+1];
int read()
void buildst()
; }
}f[n];
struct segtree
void pushdown(int x)
; } }
void update(int x,int l,int r,int ql,int qr,node v)
pushdown(x);
int mid=(l+r)>>1;
if (ql<=mid) update(x*2,l,mid,ql,qr,v);
if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
pushup(x); }
node query(int x,int l,int r,int ql,int qr)
; if (ql<=l && qr>=r) return val[x];
pushdown(x);
int mid=(l+r)>>1; node res=(node);
if (ql<=mid) res=res+query(x*2,l,mid,ql,qr);
if (qr>mid) res=res+query(x*2+1,mid+1,r,ql,qr);
return res;
}}seg;
void solve(int l,int r)
int mid=getmin(l+1,r);
solve(l,mid-1);
int ll=mid,rr=r,mm,pos;
while (ll<=rr)
pos=ll-1;
// part 1
node res=seg.query(1,0,n,l,max(mid-c[mid],l));
for (int i=max(mid,l+c[mid]);i<=pos;i++)
// part 2
res=seg.query(1,0,n,l,mid-1);
seg.update(1,0,n,mid+c[mid],pos,res);
// part 3
for (int i=pos+1;i<=r;i++)
solve(mid,r);
}int main()
for (int i=1;i<=n;i++) d[i]=n-c[i]+1;
buildst();
f[0]=(node);
solve(0,n);
if (f[n].c) printf("%d %d",f[n].v-1,f[n].c);
else printf("-1");
return 0;
}
YbtOJ 752 最優分組 笛卡爾樹,線段樹
n 個人,每個人有 c i 和 d i 分別表示這個人所在的隊伍的最少 最多人數。然後要求將這些人分成編號連續的若干隊使得隊伍最多,並且求分隊方案數。1 leq n leq 10 6 陰間題目.為了方便計算先定義乙個結構體 包含答案和方案數 和加法運算表示取最大值 相同加方案數作為答案。設 f i ...
YbtOj練習 貪心3 最優密碼
這道題暴力拿了90分,正解實在不會寫!因為字串不好操作,所以乾脆把它變成乙個int的陣列,最後輸出時直接把數字轉換成字元輸出。首先考慮我們的貪心策略 下標從1開始 設k為我們已經處理過的位置的個數,初始時k 0。只要我們的操作次數還有剩餘,那麼就考慮第k 1個位置能通過交換操作得到的最小的數字是多少...
ybtoj 二分演算法 最小時間
有n個物品,第i個物品有兩個屬性k,b,表示它在時刻 的價值為k x b。當前處於時刻0,你可以選擇不超過m個物品,使得存在非負整數時刻t,你選擇的所有物品的總價值大於等於s。給出s,求t的最小值。第一行三個整數n,m,s。接下來n行,第i行兩個整數k,b。一行乙個整數表示答案。3 2 100 3 ...