【BZOJ3316】JC loves Mkk 分数规划+单调队列

【BZOJ3316】JC loves Mkk

Description

Input

第1行,包含三个整数。n,L,R。
第2行n个数,代表a[1..n]。

Output

仅1行,表示询问答案。
如果答案是整数,就输出整数;否则,输出既约分数“P/Q”来表示。

Sample Input

5 3 4
3 1 2 4 5

Sample Output

7/2
HINT
1≤L≤R≤n≤10^5,0≤ai≤10^9,保证问题有解,数据随机生成

题解:直接二分答案,然后每个糖果的权值都变成a[i]-mid,我们需要找到一段长度在[L,R]中的区间使得权值和>=0。然后我们将区间和转变成前缀相减的形式,所以只需要找到s[j]<s[i],j<i这样的i,j就行了。那么对于每个s[i],我们肯定是贪心地选取前面最小的s[j],这个用单调队列维护即可。

但是要求区间长度是偶数,所以我们需要开对奇偶各开一个单调队列。同时要求答案是分数,这个是需要再最后算一下就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
typedef long long ll;
using namespace std;
const int maxn=100010;
int n,L,R,h1,t1,h2,t2;
ll ans1,ans2,g;
ll A[maxn<<1],S[maxn<<1];
double v[maxn<<1],s[maxn<<1];
int q1[maxn<<1],q2[maxn<<1];
ll gcd(ll a,ll b)
{
	return (!b)?a:gcd(b,a%b);
}
bool check(double x)
{
	int i;
	for(i=1;i<=n<<1;i++)	v[i]=A[i]-x,s[i]=s[i-1]+v[i];
	h1=h2=t1=1,t2=0,q1[1]=0;
	for(i=L;i<=n<<1;i++)
	{
		while(h1<=t1&&q1[h1]<i-R)	h1++;
		while(h2<=t2&&q2[h2]<i-R)	h2++;
		if(!(i&1)&&h1<=t1&&s[q1[h1]]<=s[i])
		{
			ans1=S[i]-S[q1[h1]],ans2=i-q1[h1],g=gcd(ans1,ans2),ans1/=g,ans2/=g;
			return 1;
		}
		if((i&1)&&h2<=t2&&s[q2[h2]]<=s[i])
		{
			ans1=S[i]-S[q2[h2]],ans2=i-q2[h2],g=gcd(ans1,ans2),ans1/=g,ans2/=g;
			return 1;
		}
		if(!((i-L+1)&1))
		{
			while(h1<=t1&&s[q1[t1]]>=s[i-L+1])	t1--;
			q1[++t1]=i-L+1;
		}
		else
		{
			while(h2<=t2&&s[q2[t2]]>=s[i-L+1])	t2--;
			q2[++t2]=i-L+1;
		}
	}
	return 0;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),L=rd(),R=rd();
	int i;
	double l=1<<30,r=0,mid;
	for(i=1;i<=n;i++)	A[i]=A[i+n]=rd(),l=min(l,(double)A[i]),r=max(r,(double)A[i]);
	for(i=1;i<=n<<1;i++)	S[i]=S[i-1]+A[i];
	for(i=1;i<=50;i++)
	{
		mid=(l+r)/2;
		if(check(mid))	l=mid;
		else	r=mid;
	}
	printf("%lld/%lld",ans1,ans2);
	return 0;
}
时间: 2024-12-26 10:10:30

【BZOJ3316】JC loves Mkk 分数规划+单调队列的相关文章

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

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3316 题意:给出一个环,求出长度在$L~R$之间任意偶数的一个序列,使得这个序列的平均值最大. 看到分数就知道这题不可做-- 好啦言归正传--这道题应该怎么做呢--直接上$PoPoQQQ$大爷的语录: 看到环果断倍增 看到平均值最大果断二分答案 看到长度[L,R]果断单调队列 没错就是这样--平均值这个东西其实就是要这么瞎搞--二分答案,然后给每个元素"咔嚓"一下去掉二分的值,之后

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

题目大意:给定一个环,要求在这个环上截取长度为偶数且在[L,R]区间内的一段,要求平均值最大 看到环果断倍增 看到平均值最大果断二分答案 看到长度[L,R]果断单调队列 对数组维护一个前缀和,对前缀和维护单调递增的单调队列 每扫过一个数sum[i],将sum[i-L]加入单调队列,再把距离i超过R的点删掉 长度为偶数?对奇数位置和偶数位置分别维护一个单调队列即可 每次找到大于0的子串之后记录一下分母再退出就行了 #include <cstdio> #include <cstring>

bzoj3316 JC loves Mkk题解

3316: JC loves Mkk Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 979  Solved: 316[Submit][Status][Discuss] Description Input 第1行,包含三个整数.n,L,R.第2行n个数,代表a[1..n]. Output 仅1行,表示询问答案.如果答案是整数,就输出整数:否则,输出既约分数"P/Q"来表示. Sample Input 5 3 4 3 1 2 4 5 Sampl

BZOJ3316 JC loves Mkk

首先断环成链,变成两倍长度. 然后二(fen)分(shu)答(gui)案(hua),查看答案为ans的长度在[L, R]之间的链存不存在. 我们可以维护前缀和,用单调队列O(n)判断是否和大于0 又学习了个黑科技...::x表示全局变量x... 1 /************************************************************** 2 Problem: 3316 3 User: rausen 4 Language: C++ 5 Result: Acce

【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列

一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解 二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的结点的深度来确定$tb数组$中的滑块. 因为分数规划要找的是$max$,BFS遍历当前结点的深度越来越大,这样滑块也是单调向右滑动,所以滑块里的最大值就应当用单调队列解决 #include<cstdio> #include<algorithm> #define read(x) x=ge

BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来.令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx.具体看代码吧TAT 代码: #include<cstring>#

bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

[Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Discuss] Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N

BZOJ 1758 Wc2010 重建计划 树的点分治+二分+单调队列

题目大意:给定一棵树,询问长度在[l,u]范围内的路径中边权的平均值的最大值 01分数规划,首先想到二分答案 既然是统计路径肯定是点分治 每次统计时我们要找有没有大于0的路径存在 那么对于一棵子树的每一个深度i记录一个路径权值和的最大值 然后在这棵子树之前的所有子树的深度可选范围就是[l-i,u-i] 这个窗口是不停滑动的 因此用单调队列维护最大值即可 ↑上面这些网上的题解都说的还是蛮详细的 据说二分套在树分治里面会快一些 但是 尼玛 我被卡常了!! 这里只提供一些剪枝 1.当前分治的总点数<=

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的