前缀和+二分

Powered by:AB_IN 局外人

P1182 数列分段 Section II

拿洛谷的一个例子记一下前缀和。
数据超过了1e5,故O(n^2)的算法又行不通,所以换二分

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,m,l,r;
ll a[1000001],sum[1000001];
inline bool check(ll mid){//用写入和布尔会快一点
	int now=0;
	int cnt=0;//计数器
	for(int i=2;i<=n;i++){
		if(sum[i]-sum[now]>mid){//如果i到now的这一段和>mid了,那么计数器+1,重新往右取区间
			cnt++;
			now=i-1;
		}
	}
	return cnt>=m;///如果最后分的区间大于等于了要分的区间,说明mid合法继续二分。
}
int main(){
    cin>>n>>m;
    cin>>a[1];
    sum[1]=a[1];
	for(int i=2;i<=n;i++){//前缀和!!!非常常用
		cin>>a[i];
		sum[i]=a[i]+sum[i-1];
		l=max(l,a[i]);//最小值为整个数组最大的数(因为求的是每段最大和的最小)
	}
	r=sum[n];//右边界是前缀和的最大值(即数组的和)
	while(l<=r){///为什么用二分呢?直接遍历也是可以的,但可能会t。二分里有区间的最大值,也有不是区间的最大值,但没关系,总会找到一个最优解,满足分段且最大值最小
		ll mid=(l+r)/2;//每个mid都对应了数组一段的和
		if(check(mid))//所有的 x'(x'<x)x ′ (x ′ <x) 都是可行解。并且,如果有一个数y是非法解,那么一般的,所有的 y'(y'>y)y ′(y ′>y) 都是非法解。
			l=mid+1;
        else
            r=mid-1;
	}
	cout<<l;
	return 0;
}

完结。
并不!

P1147 连续自然数和

今天看完清楚姐姐的直播,感觉又明白了许多,赶紧拿一个练练手……
二分+前缀和,太典型了,但是这样反而跑的比较慢。

#include <iostream>
typedef long long ll;
using namespace std;
ll a[2000002],n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        a[i]+=a[i-1]+i;
    for(int i=1;i<=n;i++){//[l,r]的和就是a[r]-a[l-1]
        ll mid=a[i-1]+n;
        ll ans=lower_bound(a+1,a+n+1,mid)-a;
        if(a[ans]-a[i-1]==n){
            if(ans!=i) cout<<i<<" "<<ans<<endl;
        }
    }
    return 0;
}

奥林oj上跑了668ms, 吸氧+改输入输出跑290ms.
看有大佬用等差数列!?还有公式!
Orz
完结。

原创文章 9 获赞 20 访问量 437

猜你喜欢

转载自blog.csdn.net/qq_45859188/article/details/106052772