2017 Multi-University Training Contest 4 hdu 6070
题意:提交了n次题目,每个题目都是最后一次提交的时候AC的,现在求一个区间,这个区间的AC率是最低的(只考虑这个区间内的题目,同样区间内最后交的一遍是AC的),求最低的AC率
思路: 线段树+二分;AC率=提交次数/题目数目,即区间长度/题目种类,siz[l,r]/(r-l+1)=p(siz[l,r]表示l r区间内的不同题目的个数,p表示AC率), 把式子做一下调整,siz[l,r]+p*l=p(r+1),二分p(0-1)用线段树维护siz[l,r]+l*p 的最小值,然后枚举r,每次更新,因为l交给线段树维护了,所以不需要考虑l的位置,题解真是666,重新认识了线段树,感谢飞哥的大力帮助@jhz033,不然我还不知道线段树维护的是什么东西,这个题式子好写,但是思路难想,代码也好拍,但是余味还可以回味一年,这种思想还是值得去品味的,这波不亏
AC代码:
#include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #pragma comment(linker, "/STACK:102400000,102400000") #define ll long long #define endl ("\n") #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ft (frist) #define sd (second) #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const long long INF = 1e18+1LL; const int inf = 1e9+1e8; const double eps=1e-4; const int N=6e4+100; const ll mod=1e9+7; int n,a[N]; double MID; struct TREE{ int lazy[N<<2]; double mi[N<<2]; void push_up(int rt){ mi[rt]=min(mi[lrt], mi[rrt]); } void push_down(int rt){ mi[lrt]+=lazy[rt]; mi[rrt]+=lazy[rt]; lazy[lrt]+=lazy[rt]; lazy[rrt]+=lazy[rt]; lazy[rt]=0; } void creat(int rt, int l, int r){ lazy[rt]=0; if(l==r){ mi[rt]=MID*l; return; } int mid=l+r>>1; creat(lrt, l, mid); creat(rrt, mid+1, r); push_up(rt); } void update(int rt, int l, int r, int L, int R){ if(L<=l && R>=r){ mi[rt]+=1; lazy[rt]+=1; return; } if(lazy[rt]!=0) push_down(rt); int mid=l+r>>1; if(L<=mid) update(lrt, l, mid, L, R); if(R>mid) update(rrt, mid+1, r, L, R); push_up(rt); } double query(int rt, int l, int r, int L, int R){ if(L<=l && R>=r){ return mi[rt]; } if(lazy[rt]!=0) push_down(rt); int mid=l+r>>1; double ans=99999999999; if(L<=mid) ans=min(ans,query(lrt, l, mid, L, R)); if(R>mid) ans=min(ans,query(rrt, mid+1, r, L, R)); return ans; } }tree; bool check(){ int pre[N]; mem(pre,0); tree.creat(1,1,n); for(int i=1; i<=n; ++i){ tree.update(1, 1, n, pre[a[i]]+1, i); double f=tree.query(1,1,n,1,i); if(f<=MID*(i+1)) return 1; pre[a[i]]=i; } return 0; } int main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int T; cin>>T; while(T--){ cin>>n; for(int i=1; i<=n; ++i){ cin>>a[i]; } double l=0, r=1, ans=0; while(r-l>=eps){ MID=(l+r)/2; if(check()){ ans=MID; r=MID; } else l=MID; } cout<<ans<<endl; } return 0; }