bzoj3316 JC loves Mkk 二分答案 单调队列

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3316

题意:给出一个环,求出长度在$L~R$之间任意偶数的一个序列,使得这个序列的平均值最大。

看到分数就知道这题不可做……

好啦言归正传……这道题应该怎么做呢……直接上$PoPoQQQ$大爷的语录:

看到环果断倍增

看到平均值最大果断二分答案

看到长度[L,R]果断单调队列

没错就是这样……平均值这个东西其实就是要这么瞎搞……二分答案,然后给每个元素“咔嚓”一下去掉二分的值,之后我们就可以寻找一个区间,这个区间的和大于等于零,这个区间就是合法的……这个东西显然可以前缀和加单调队列优化……由于长度必须是偶数所以必须开两个单调队列……

还有就是……

用long double!不然炸精会炸的很惨!

用long double!不然炸精会炸的很惨!

用long double!不然炸精会炸的很惨!

重要的事情说三遍!别问我怎么知道的……

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=100005;
 7 long double sum[maxn<<1];long long dodo;
 8 int a[maxn<<1],n,L,R,q[2][maxn<<1],h[2],t[2];
 9 long long gcd(long long a,long long b){return !b?a:gcd(b,a%b);}
10 const double eps=1e-6;
11 bool check(long double val)
12 {
13     for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]-val;
14     h[0]=h[1]=1,t[0]=t[1]=0;
15     for(int i=L;i<=n;i++)
16     {
17         int k=i&1,x=i-L;
18         while(h[k]<=t[k]&&sum[x]<=sum[q[k][t[k]]])t[k]--;
19         while(h[k]<=t[k]&&q[k][h[k]]<i-R)h[k]++;
20         q[k][++t[k]]=x;
21         if(sum[i]-sum[q[k][h[k]]]>=eps)return dodo=i-q[k][h[k]];
22     }
23     return 0;
24 }
25 int haha()
26 {
27     scanf("%d%d%d",&n,&L,&R);if(L&1)L++;if(R&1)R--;
28     for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i];n<<=1;
29     long double l=0,r=1e9,mid,ans=0;
30     while(r-l>eps)
31     {
32         mid=(l+r)/2;
33         if(check(mid))l=ans=mid;
34         else r=mid;
35     }
36     long long fenzi=(long long)(dodo*ans+0.5),fenmu=dodo;
37     long long g=gcd(fenzi,fenmu);fenzi/=g,fenmu/=g;
38     printf("%lld",fenzi);if(fenmu>1)printf("/%lld
",fenmu);
39 }
40 int sb=haha();
41 int main(){;}
bzoj3316
原文地址:https://www.cnblogs.com/Loser-of-Life/p/7574163.html