Binary Search + Line Segment Tree + Enumeration
Topic:
In the ACM-ICPC competition, there will be many different situations in submitting a topic. Now we give all the submissions of a team. Only AC and WA are given in sequence. The last time the same number appears is AC, which defines an interval.
That is to say, divide the number of AC in the whole interval by the total number of submissions, and find out what the minimum ratio is.
Ideas:
In fact, the meaning of the question is not very clear. The range of the number given is 1-60000, and any sub-interval can be submitted as a complete topic. That is to say, the number of AC is the total number of different numbers appearing in the sub-interval, and the length of the interval is the total number of submissions. I was wrong when I understood, but fortunately there was discuss ion... Nevertheless, I didn't expect such a powerful line segment tree method.
There are many sub-intervals in the range of 60,000, so we can't write violently! __________ Dirt Ratio ranges from 0 to 1, and the accuracy is
Definition:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 60005;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
int n;
int a[maxn],lastAppear[maxn];
struct Node
{
int l,r;
double sum;
double lazy;
}tree[maxn<<2];
void Push_up(int root)
{
tree[root].sum = min(tree[root<<1].sum,tree[root<<1|1].sum);
}
void Push_down(int root)
{
tree[root<<1].sum += tree[root].lazy;
tree[root<<1].lazy += tree[root].lazy;
tree[root<<1|1].sum += tree[root].lazy;
tree[root<<1|1].lazy += tree[root].lazy;
tree[root].lazy = 0;
}
void build(int root,int l,int r,double v)
{
tree[root].l = l,tree[root].r = r;
tree[root].lazy = 0;
if(l == r) {
tree[root].sum = (long long)l*v;
return ;
}
int mid = (l+r)>>1;
build(root<<1,l,mid,v);
build(root<<1|1,mid+1,r,v);
Push_up(root);
}
void UpDate(int L,int R,int root,int v)
{
if(L <= tree[root].l && tree[root].r <= R) {
tree[root].sum += v;
tree[root].lazy += v; /*lazy Let the sum of subintervals increase v as a whole, so sum += v*/
return ;
}
if(tree[root].lazy != 0) Push_down(root);
int mid = (tree[root].l + tree[root].r)>>1;
if(L <= mid) UpDate(L,R,root<<1,v);
if(R > mid) UpDate(L,R,root<<1|1,v);
Push_up(root);
}
double queryMinSum(int L,int R,int root)
{
if(L <= tree[root].l && tree[root].r <= R) {
return tree[root].sum;
}
if(tree[root].lazy != 0) Push_down(root);
double ans = INF;
int mid = (tree[root].l + tree[root].r)>>1;
if(L <= mid) ans = queryMinSum(L,R,root<<1);
if(R > mid) {
double temp = queryMinSum(L,R,root<<1|1);
if(temp < ans)
ans = temp;
}
return ans;
}
int judge(double mid)
{
build(1,1,n,mid); /*More mid than conventional tree building, in fact, is a perfect pretreatment*/
for(int i = 1;i <= n; i++) lastAppear[i] = 0;
for(int i = 1;i <= n; i++) {
UpDate(lastAppear[a[i]]+1,i,1,1);
lastAppear[a[i]] = i;
if(queryMinSum(1,i,1) <= mid*(i+1)) return true;
}
return false;
}
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
int tt;
scanf("%d",&tt);
while(tt--) {
scanf("%d",&n);
for(int i = 1;i <= n; i++) scanf("%d",&a[i]);
double l = 0,r = 1,mid,ans;
while(r - l > eps) {
mid = (r+l)/2;
if(judge(mid)) r = (ans = mid) - eps;
else l = mid + eps;
}
printf("%.9f\n",ans);
}
return 0;
}