傳送門
此題的題意不是很清晰,要注意的一點是在區間[l,r]中,預設題目編號最後一次出現的時候是ac的
比如1 2 1 2 3 ,在區間[1,4]中,第3次提交時ac第1題,第4次提交時ac第2題,故比例為2/4=0.5
所以此問題可以轉化為
給定乙個序列,定義區間[l,r]的值為cn
t(l,
r)r−
l+1' role="presentation" style="position: relative">cnt
(l,r
)r−l
+1cn
t(l,
r)r−
l+1,(cnt(l,r)為區間中不同元素的個數,求值最大的區間,輸出其最大值
1.二分答案
很明顯此題用直接列舉區間的方法會超時,必須使用二分來降低時間複雜度
如果二分區間端點,則答案不存在單調性,無法二分
因此二分答案,顯然答案可取的範圍是[0,1)
設二分中點為mid,由題意cn
t(l,
r)r−
l+1≤
mid' role="presentation" style="position: relative">cnt
(l,r
)r−l
+1≤m
idcn
t(l,
r)r−
l+1≤
mid ([l,r]為所有區間中值最小的區間)
兩邊同乘化簡r-l+1,移項,整理得cn
t(l,
r)+m
id×l
≤mid
×(r+
1)' role="presentation" style="position: relative">cnt
(l,r
)+mi
d×l≤
mid×
(r+1
)cnt
(l,r
)+mi
d×l≤
mid×
(r+1
)2.求不等式左邊的值,判斷mid是否可取到
對於每次二分,列舉r從1~n,對於每乙個r,我們再求右端點為r的所有區間的所有區間的值中的最小值
我們維護一棵線段樹,線段數的每個葉子節點l表示左端點為l,右端點為r(當前的列舉值)時的值,再統計區間[1,r]最小值
這樣我們就求出了右端點為r的所有區間的值中的最小值
由於r從1~n,線段樹中的值也在不斷變化,我們怎麼更新線段樹中的值呢?
每次r+1,需要更新[r,r]這個區間,區間加mi
d×r' role="presentation" style="position: relative">mid
×rmi
d×r,
再更新[x,r]各區間的cnt值,設a上一次出現的位置為last[a],則區間[last[a]+1,r]都需要+1,因為區間內出現了乙個新的數a,而對於last[a]之前的位置,由於a已經出現過,cnt值不受影響
時間複雜度分析:
二分時間複雜度為o(
log2
1ϵ)' role="presentation" style="position: relative">o(l
og21
ϵ)o(
log2
1ϵ),其中
ϵ' role="presentation" style="position: relative">ϵ
ϵ為精度,在此題中設ϵ=
10−5' role="presentation" style="position: relative">ϵ=10
−5ϵ=
10−5即可
線段樹的建樹時間複雜度為o(
nlog
2n)' role="presentation" style="position: relative">o(n
log2
n)o(
nlog
2n),n次插入與查詢時間複雜度為o(
nlog
2n)' role="presentation" style="position: relative">o(n
log2
n)o(
nlog
2n)
所以總的時間複雜度分析為o(
nlog
2n×l
og21
ϵ)' role="presentation" style="position: relative">o(n
log2
n×lo
g21ϵ
)o(n
log2
n×lo
g21ϵ
)
#include
#include
#include
#include
#define maxn 60005
#define eps 1e-5
#define inf 0x7fffffff
using
namespace
std;
int a[maxn];
int pos[maxn],last[maxn];
struct node
}tree[maxn<<2];
void push_up(int pos)
void build(int l,int r,int pos)
void push_down(int pos)
}void update(int l,int r,double v,int pos)
push_down(pos);
int mid=(l+r)>>1;
if(l<=mid) update(l,r,v,pos<<1);
if(r>mid) update(l,r,v,pos<<1|1);
push_up(pos);
}double query(int l,int r,int pos)
push_down(pos);
int mid=(l+r)>>1;
double ans=inf;
if(l<=mid) ans=min(ans,query(l,r,pos<<1));
if(r>mid) ans=min(ans,query(l,r,pos<<1|1));
return ans;
}int t,n;
int main()
for(int i=1;i<=n;i++)
double l=0,r=1;
double ans=inf;
while(fabs(l-r)>eps)
}if(is_min)
else l=mid;
}printf("%lf\n",ans);
}}
hdu6070 線段樹 二分
題意給你乙個區間,讓你找,區間種類數 區間長度最小是多少。思路先公式化簡 size r l 1 mid size l 1 mid r mid mid是二分的值 對於每乙個元素a i 他能影響的區間是,last a i 1 到i last表示這個這個元素上一次出現的位置 他能讓這個區間的種類數 1,由...
線段樹 二分 HDU6070
題目讓我們求type l,r r l 1 的最小,顯然可以用01分數規劃,來二分求最小答案。所以我們從左往右移動端點,來統計種類。線段樹來維護type l,r l mid的值。include using namespace std const int n 1e6 7 const double eps...
hdu 6070 二分答案 線段樹
題意 區間價值為 區間元素種類數 區間長度 問最小價值的區間是?思路 直接求解很困難,考慮二分答案判斷,注意這題的關鍵是將二分答案後的不等式進行變換,如官方題解。二分答案 mid,檢驗是否存在乙個區間滿足 size l,r r l 1 mid,也就是 size l,r mid l mid r 1 之...