BZOJ3316: JC loves Mkk

二分 单调队列

题目传送门

套路断环为链。二分答案mid(用long double),记一个前缀和 s [ i ] = s [ i − 1 ] + w [ i ] − m i d s[i]=s[i-1]+w[i]-mid s[i]=s[i1]+w[i]mid,那么我们只要判断是否有一段长度为偶数且 s [ r ] − s [ l − 1 ] ≥ 0 s[r]-s[l-1]\geq0 s[r]s[l1]0即可。

用单调队列维护 s [ i ] s[i] s[i]的最小值。保证长度为偶数的话用两个分奇偶维护。

二分完后我们可以得到分母,乘上答案四舍五入就可以得到分子。

这道题充满了套路。。。

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define F inline
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef long double DB;
int n,L,R,mx,w[N],q[2][N];
DB s[N]; LL ans1,ans2;
F char readc(){
	static char buf[100000],*l=buf,*r=buf;
	if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
	return l==r?EOF:*l++;
}
F int _read(){
	int x=0; char ch=readc();
	while (!isdigit(ch)) ch=readc();
	while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
	return x;
}
F LL gcd(LL a,LL b){ return !b?a:gcd(b,a%b); }
bool pd(DB mid){
	for (int i=1;i<=n;i++) s[i]=s[i-1]+w[i]-mid;
	int l[2]={1,1},r[2]={0,0};
	for (int i=L;i<=n;i++){
		int p=i-L,x=i&1;
		while (l[x]<=r[x]&&s[p]<s[q[x][r[x]]]) r[x]--;
		q[x][++r[x]]=p; if (i-q[x][l[x]]>R) l[x]++;
		if (s[i]-s[q[x][l[x]]]>0) return ans2=i-q[x][l[x]],true;
	}
	return false;
}
int main(){
	n=_read(),L=_read(),R=_read(),L+=L&1,R-=R&1;
	for (int i=1;i<=n;i++) w[i]=w[i+n]=_read(),mx=max(mx,w[i]);
	DB l=0,r=mx,mid; n<<=1;
	while (r-l>eps) pd(mid=(l+r)/2)?l=mid:r=mid;
	ans1=(LL)((l+r)/2*ans2+0.5);
	LL t=gcd(ans1,ans2); ans1/=t,ans2/=t;
	return ans2==1?printf("%lld",ans1):printf("%lld/%lld",ans1,ans2),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值