[二分答案 单调队列] BZOJ 3316 JC loves Mkk


%%%PoPoQQQ:http://blog.csdn.net/popoqqq/article/details/43059527


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

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

对数组维护一个前缀和,对前缀和维护单调递增的单调队列

每扫过一个数sum[i],将sum[i-L]加入单调队列,再把距离i超过R的点删掉

长度为偶数?对奇数位置和偶数位置分别维护一个单调队列即可

每次找到大于0的子串之后记录一下分母再退出就行了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[1000000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline ll GCD(ll a,ll b){
	return b?GCD(b,a%b):a;
}

int n,L,R;
int maxa,a[200005];
double sum[200005];
ll iP,iQ,D;
int Q[2][200005],l[2],r[2];

inline bool Check(double mid)
{
	for (int i=1;i<=n;i++)
		sum[i]=sum[i-1]+a[i]-mid;
	l[0]=l[1]=r[0]=r[1]=-1;
	for (int i=L;i<=n;i++)
	{
		int *Q=::Q[i&1],&r=::r[i&1],&l=::l[i&1],x=i-L;
		while (l<r && sum[Q[r]]>sum[x])
			Q[r--]=0;
		Q[++r]=x;
		while (i-Q[l+1]>R)
			Q[++l]=0;
		if(sum[i]-sum[Q[l+1]]>=0)  
            return iQ=i-Q[l+1];    
	}
	return 0;
}

inline double Bin(){
	double L=0,R=maxa,MID;
	while (R-L>=1e-6)
		if (Check(MID=(L+R)/2))
			L=MID;
		else
			R=MID;
	return (L+R)/2;
}

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(L); read(R);
	if(L&1) L++; if(R&1) R--; 
	for (int i=1;i<=n;i++)
		read(a[i]),a[n+i]=a[i],maxa=max(maxa,a[i]);
	n<<=1;
	iP=(ll)(Bin()*iQ+0.5);
	D=GCD(iQ,iP);
	iP/=D; iQ/=D;
	if (iQ==1)
		printf("%lld\n",iP);
	else
		printf("%lld/%lld\n",iP,iQ);
	return 0;
}


你可能感兴趣的:([二分答案 单调队列] BZOJ 3316 JC loves Mkk)