首页 > 其他分享 >二分+前缀和——洛谷P1314

二分+前缀和——洛谷P1314

时间:2024-03-13 22:31:36浏览次数:40  
标签:洛谷 前缀 mid long 200010 P1314 数组 ans

1.公式解读

[...]   括号内内容为真则其值等于1,内容为假则其值等于0 

2.思路

这是一个关于单调性判定的问题,当W不断增大,差值由大变小再变大(实际是从负到0到正,只不过要取绝对值,不影响它的单调性),而目标则是在0的附近找到一个绝对值最小的值,因此是一道二分答案题,但如果只用二分法会超时。我们在计算一个区间的和时,通常是用前缀和的方法来缩减时间,直接模拟是n2,而前缀和优化成2∗n。

3.核心代码

while (l<=r)
{
	y=0,mid=l+(r-l)/2;
	for (i=1;i<=n;i++)
	{
		if (w[i]>=mid)
			a[i]=a[i-1]+1,b[i]=b[i-1]+v[i];
		else
			a[i]=a[i-1],b[i]=b[i-1];
	}
	for (i=1;i<=m;i++)
		y+=(a[ri[i]]-a[le[i]-1])*(b[ri[i]]-b[le[i]-1]);
	d=y-s;
	if (d>0)	
        l=mid+1;
	else
    	r=mid-1;
	ans=min(ans,abs(d));
}

4.代码片段分析

(1)求前缀和

for (i=1;i<=n;i++)
{
	if (w[i]>=mid)
		a[i]=a[i-1]+1,b[i]=b[i-1]+v[i];
	else
		a[i]=a[i-1],b[i]=b[i-1];
}

1)循环条件是 i <= n,你可能会疑惑不应该是公式中在区间内的编号才要计算吗,就像图中这样

但是请注意,上述代码还未进行到公式这一步,而是在进行前缀和,可以理解为在预处理。既然是求前缀和,那自然是要整个数组。

2)在这个while循环中,每一次都是一个不同的W(判断值),因此每一次循环的前缀和数组值都不一样

3)我们需要在脑海中想象一个大小为n的数组,若其下标 i 对应的矿石满足条件,则这个数组中以 i 为下标对应的值为 1 ,否则为 0 。

然后开始前缀和,a数组是前缀和数组,对象是上面的n数组,因为要的是满足条件的个数,所以是加 1 。b数组也是前缀和数组,对象是矿石价值数组,所以是加上矿石价值。

(2)带入公式

for (i=1;i<=m;i++)
	y+=(a[ri[i]]-a[le[i]-1])*(b[ri[i]]-b[le[i]-1]);

1)这里的循环条件是 i <= m,处理每一个区间。

2)( a [ ri [ i ] ] - a [ le [ i ] - 1 ] )   对应区间左右边界(ri [ i ] 是右边界,le [ i ] 是左边界),b [ ri [ i ] ] - b [ le [ i ] - 1 ]   对应矿石价值前缀和。

3)y+=   而不是   y=  ,因为是累加各区间和。

(3)二分答案

while (l<=r)
{
    ...
    ...
    d=y-s;
    if (d>0)	
        l=mid+1;
    else
        r=mid-1;
    ans=min(ans,abs(d));
}

二分答案模版,只是把记录答案的位置移到下面去了。不能提前取绝对值,因为要判断差值正负来调整mid,而是在每一次更新答案的时候取绝对值。

5.细节

long long n,m,s,y,d,ans;
long long w[200010],v[200010],le[200010],ri[200010],a[200010],b[200010];
long long l,r,mid;

三处long long,你可能要问为什么 l ,r ,mid 也要long long。

for (i=1;i<=n;i++)
{
	cin>>w[i]>>v[i];
	l=min(l,w[i]);
	r=max(r,w[i]);
}

在读入数据时要找到最大和最小的矿石重量,而min和max函数要求内部参数一致,不能一个int一个long long,实际上w数组没必要long long ,只是定义数组时和a,b数组定义在了一起,而这两个数组要long long,如果你要分开来定义想换成int也无伤大雅,这里只是想提一点min,max函数内部参数可能出现的问题。

6.完整代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

long long n,m,s,y,d,ans;
long long w[200010],v[200010],le[200010],ri[200010],a[200010],b[200010];

int main()
{
	int i;
	long long l,r,mid;
	l=1e6,r=0,ans=1e15;
	cin>>n>>m>>s;
	for (i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
		l=min(l,w[i]);
		r=max(r,w[i]);
	}
	for (i=1;i<=m;i++)
		cin>>le[i]>>ri[i];
	while (l<=r)
	{
		y=0,mid=l+(r-l)/2;
		for (i=1;i<=n;i++)
		{
			if (w[i]>=mid)
				a[i]=a[i-1]+1,b[i]=b[i-1]+v[i];
			else
				a[i]=a[i-1],b[i]=b[i-1];
		}
		for (i=1;i<=m;i++)
			y+=(a[ri[i]]-a[le[i]-1])*(b[ri[i]]-b[le[i]-1]);
		d=y-s;
		if (d>0)	
			l=mid+1;
		else	
			r=mid-1;
		ans=min(ans,abs(d));
	}
	cout<<ans;
	return 0;
}

标签:洛谷,前缀,mid,long,200010,P1314,数组,ans
From: https://blog.csdn.net/2301_81608637/article/details/136563353

相关文章

  • 高维前缀和(SOS DP)
    引入方法在讨论高维前缀和前,不妨先回顾以下二维前缀和,一种写法是:for(inti=1;i<=w;i++) for(intj=1;j<=w;j++)sum[i][j]+=sum[i][j-1]for(inti=1;i<=w;i++) for(intj=1;j<=w;j++)sum[i][j]+=sum[i-1][j]推广......
  • 洛谷P6866 [COCI2019-2020#5] Emacs
    题目描述给定一个n×m 的只含有 . 和 * 的矩阵。矩阵中 * 形成一些不重叠的长方形。它们不在边缘或顶点接触。求长方形有多少个?输入格式第一行:两个正整数 n 和 m。以下 n 行:表示题目描述中的矩阵。矩阵只含有 . 和 *。输出格式一行一个非负整数,你的答......
  • C++:[NWRRC2015] Concatenation(洛谷)P7050
    题目描述FamousprogrammerGennadylikestocreatenewwords.Onewaytodoitistoconcatenateexistingwords.Thatmeanswritingonewordafteranother.Forexample,ifhehaswords cat and dog,hewouldgetaword catdog,thatcouldmeansomething......
  • 洛谷 P2730 魔板 题解 DFS(广度优先搜索)
    题目背景在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有 8 个大小相同的格子的魔板:12348765题目描述我们知道魔板的每一个方格都有一种颜色。这 8 种颜色用前 8 个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左......
  • 洛谷题单指南-二叉树-P4715 【深基16.例1】淘汰赛
    原题链接:https://www.luogu.com.cn/problem/P4715题意解读:计算亚军得主,注意能力值最高的肯定是冠军,但能力值第二高的不一定是亚军,因为有可能中途就遭遇冠军。解题思路:根据题意,两两比赛,一轮后再按顺序两两比赛,形如一棵二叉树,但解题其实用不到二叉树的数据结构可以看出,最后参与......
  • 每日一题 第一期 洛谷 铺地毯
    [NOIP2011提高组]铺地毯https://www.luogu.com.cn/problem/P1003题目描述为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n......
  • 「杂题乱刷」洛谷 P2572
    先上AC代码:点击查看代码/*Tips:你数组开小了吗?你MLE了吗?你觉得是贪心,是不是该想想dp?一个小时没调出来,是不是该考虑换题?*/#include<bits/stdc++.h>usingnamespacestd;#definemapunordered_map#defineforl(i,a,b)for(registerlonglongi=a;i<=b;i++)#define......
  • 洛谷题单指南-线性表-P2234 [HNOI2002] 营业额统计
    原题链接:https://www.luogu.com.cn/problem/P2234题意解读:要计算每一天最小波动值的和,需要对每一天求最小波动值,再求和,如果暴力法,时间复杂度在1+2+3+......+32767≈5*10^8,可能会超时。解题思路:1、暴力法:由于本题测试数据比较水,实测暴力求解直接可以AC,由于没有技术含量,不做具体......
  • 【算法训练营】邓老师书,子序列,前缀(python实现)
    邓老师数时间限制:1sec空间限制:256MB问题描述众所周知,大于1的自然数中,除了1与其本身外不再有其他因数的数称作质数(素数)。对于大于1的不是质数的自然数,我们又称作合数。参加了邓老师算法训练营的小Z突发奇想,定义了新的数:所有合数中,除了1与其本身外,其他因......
  • 二分答案&前缀和&差分&离散化(简记)
    二分答案基本codeintFind(intl,intr){ intans,mid; while(l<=r) { intmid=l+r>>1; if(Check(mid))ans=mid,r=mid-1;//舍弃右半部分 elsel=mid+1;//舍弃左半部分 } returnans;}前缀和基本code#inlcude<bits/stdc++.h>usingnamespacestd;intsum[100......