Daliy Algorithm(二分) -- day 53

Nothing to fear

those times when you get up early and you work hard; those times when you stay up late and you work hard; those times when don’t feel like working — you’re too tired, you don’t want to push yourself — but you do it anyway. That is actually the dream. That’s the dream. It’s not the destination, it’s the journey. And if you guys can understand that, what you’ll see happen is that you won’t accomplish your dreams, your dreams won’t come true, something greater will. mamba out


那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

2020.4.9


慢慢来 打好基础

递增三元组

二分的解法可以达到\(O(nlogn)\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>

using namespace std;
typedef long long ll;
const int N = 100005;
int A[N] , B[N] , C[N] ;
int sum[N] , n;
ll ans;
void init()
{
	cin >> n;
	for(int i = 0;i < n ;i ++)scanf("%d",&A[i]);
	for(int i = 0;i < n ;i ++)scanf("%d",&B[i]);
	for(int i = 0;i < n ;i ++)scanf("%d",&C[i]);

	sort(A , A + n);
	sort(C , C + n);
	sort(B , B + n);
}


int main()
{
	init();
	for(int i = 0;i < n ;i ++)
	{
		//找到A中第一个大于等于B[i]的元素/最后一个小于等于B[i]的坐标
		int l = 0 , r = n - 1;
		while(l < r)
		{
			int mid = l + r + 1 >> 1;
			if(A[mid] < B[i])l = mid;
			else r = mid - 1;
		}
		int t = 0;
		if(A[l] >= B[i])l = -1;
		t = l;
		l = 0, r = n - 1;
		while(l < r)
		{
			int mid = l + r >> 1;
			if(C[mid] > B[i])r = mid;
			else l = mid + 1;
		}
		if(B[i] >= C[r])r = n;
		int right = r;
		ans += (ll)(n - right ) * (t + 1);
	}
	cout << ans << endl;
	return 0;
}

lg-p1024 一元三次方程求解

思路: 实数域二分
但是题目中说了两个根之间差的绝对值大于等于1
故我们应该在( i , i + 1) 之间搜索答案

判断划分区间是否存在根只需要判断
l - mid : f(l) * f(mid) < 0  // 根在左边区间
mid - r :  f(r) * f(mid) < 0  // 根在右边区间
由于判断根重复所以 f(l) 和 f(r) 只需要判断一个即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>

using namespace std;
double a , b , c , d;
int s = 0 , t1 , t2;
double f(double x)
{
	return a*(x*x*x) + b*x*x + c*x + d; 
}
void bs(double l, double r)
{
	if(r - l <= 0.001){
		printf("%.2f ",l);
		return;
	}
	double mid = (l + r) / 2;
	double ansl , ansr;
	ansl = f(l) * f(mid);
	ansr = f(r) * f(mid);
	if(f(mid) == 0)printf("%.2f ",mid);
	if(f(r) == 0)printf("%.2f ",r);
	if(ansl < 0)bs(l , mid);
	else if(ansr < 0)bs( mid , r);
}
int main()
{
	cin >> a >> b >> c >> d;
	for(int i = -100 ;i <= 99 ;i ++)
	{
		if(f(i) * f(i + 1.0) <= 0)
			bs(i , i + 1.0);
	}
	return 0;
}

lg-p1182数列分段

思路: 二分 + 贪心
本体的目标是寻找最大值中的最小值:
1.采用二分的思路一定要答案是一个单调序列
2.由于是最大值中的最小值所以左边的边界一定是数组当中组大的哪一个当作独立分组r=所有和

3. check() 条件采用贪心的思路 : 
如果当前分组满足二分的当前答案就持续分
如果拿到下一个数不满足当前二分的最大值就划分
最后判断分组的个数是否合法 如果合法就让 r = mid
否则 l = mid + 1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>

using namespace std;
const int N = 1000005;
int n , m , l , r;
int a[N];
bool check(int x)
{
	int sum = 0 , cnt = 0;
	for(int i = 1;i <= n ;i ++)
	{
		if(sum + a[i] <= x)sum += a[i];
		else sum = a[i],cnt++;
	}
	return cnt + 1 <= m;
}

int main()
{
	int x = 0;
	cin >> n >> m;
	for(int i = 1;i <= n ;i ++)
	{
		scanf("%d",&a[i]);
		r += a[i];l = max(l , a[i]);
	}
	//确保答案一定在这个区间
	while(l < r)
	{
		int mid = l + r >> 1;
		if(check(mid))r = mid;
		else l = mid + 1;
	}
	cout << l << endl;
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/wlw-x/p/12670250.html