【蓝桥杯专题】二分&前缀和 (C++ | acwing | 洛谷 |蓝桥杯)

在这里插入图片描述

  • 板刷!!! !

二分模板

//查找左边界 SearchLeft 简写SL
int SL(int l, int r)
{
    
    
    while (l < r)
    {
    
    
        int mid = l + r >> 1;
        if (check(mid)) r = mid; 
        else l = mid + 1; 
    }   
    return l;
}
//查找右边界 SearchRight 简写SR 
int SR(int l, int r) 
{
    
    
    while (l < r)
    {
    
                       
        int mid = l + r + 1 >> 1; //需要+1 防止死循环
        if (check(mid)) l = mid;
        else r = mid - 1; 
    }
    return r; 
}

前缀和模板

一维前缀和 :

s[i] = s[i - 1] + a[i];

二维前缀和

s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1])

acwing 796. 子矩阵的和

题目连接

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int n, m, q;
const int N = 1010;
int s[N][N], a[N][N];

int main () {
    
    
    cin >> n >> m >> q;
    
    for(int i = 1; i <= n; i ++) {
    
    
        for(int j = 1; j <= m; j ++) {
    
    
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    }
    
    while (q -- ) {
    
    
        int x1, x2, y1, y2;
        cin >> x1 >> y1 >> x2 >> y2;    
        cout << s[x2][y2] -  s[x1 - 1][y2] -  s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
    }
    return 0;
}

前缀和模板题

题目 链接

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 100010;

int a[N], s[N];

int n, m, l, r;

int main (){
    
    
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) {
    
    
        cin >> a[i];
    }
    for(int i = 1; i <= n; i ++) {
    
    
        s[i] = s[i - 1] + a[i];
    }
    while(m -- ) {
    
    
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;
    }
    
    return 0;
}

四平方和 (哈希)

题目链接
在这里插入图片描述

思路 : 哈希存储 cd集合 然后枚举 ab 时间复杂度O(n 2)

#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;

const int N = 5000010;
int n;
int C[N], D[N];

void solve() {
    
    
	cin >> n;
	memset(C, -1, sizeof C);

	for(int c = 0; c * c <= n; c ++) {
    
     
		for(int d = c; d * d + c * c <= n; d ++) {
    
    
			int s = c * c + d * d;  // 哈希存储所有和的 集合
			if(C[s] == -1) {
    
    
				C[s] = c, D[s] = d;
			}
		}
	}

	for(int a = 0; a * a <= n; a ++) {
    
    
		for(int b = a; b * b + a * a <= n; b ++) {
    
    
			int t = n - a * a - b * b;
			if(C[t] != -1) {
    
     // 如果和在集合中
				cout << a << ' ' << b << " " << C[t] << ' ' << D[t] << endl; 
				return ;
			}
		}
	}
    
}

// void solve () {
    
    

// }

int main(void){
    
    
// 	freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

分巧克力 ( 二分 )

题目链接
在这里插入图片描述

思路 : 二分 ! 条件 : 每块巧克力可以分的个数 之和 与人数做对比

#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 1e5 + 10;

int n, m;
int h[N], w[N];

bool check (int mid) {
    
    
    //判断条件 : 拆剪巧克力个数  大于人数 则返回true
    // 否则 返回 false 

    ll res = 0;
    for(int i = 0; i < n; i ++) {
    
    
        res += (ll)h[i] / mid *(ll) (w[i] / mid);
        if(res >= m) return true;
        // 乘积的下取整   与 下取整后乘积 结果不同!!
        // 需要 下取整后 再 乘积
    }
    return false;
}

void solve () {
    
    
    cin >> n >> m;
    for(int i = 0; i < n ; i ++) {
    
    
        cin >> h[i] >> w[i];
    }

    int l = 1, r = 1e5 + 10;

	//因为是最大值  所以查找左边界
    while (l < r) {
    
    
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }

    cout << r << endl;
}

int main(void){
    
    
// 	freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

K倍区间 (前缀和)

题目链接

思路 :
结论:%k,余数相同的相减 = k的倍数 – >
数学思路 统计余数相同的前缀和,如果在这些前缀和中余数相同的任取俩个相减,他们得到的余数都是相同的。在这里插入图片描述

在这里插入图片描述

#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 1e5 + 10;

int n, k;
ll a[N], cnt[N];

void solve () {
    
    
    cin >> n >> k;
    for(int i = 1; i <= n; i ++) {
    
    
        cin >> a[i];
        a[i] += a[i - 1];
    }
    ll res = 0;
    cnt[0] = 1;
    rep(i, 1, n) {
    
    
        res += cnt[a[i] % k];
        cnt[a[i] % k] ++;   
    }
    cout << res << endl;

    return;

}

int main(void){
    
    
	freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

激光炸弹

题目链接

思路 :

#include <iostream>
using namespace std;
const int N = 5010;
int s[N][N];//c++ 大数组开全局
int main () {
    
    
    int N,R;// C++重名优先使用局部变量
    cin >> N >> R;
    R = min (R, 5001);
    int n = R,m = R; 
    for (int i = 0,x,y,w; i < N; i ++) {
    
    
        cin >> x >> y >> w;
        s[x+1][y+1] += w;
        //映射到1 ,为了满足题意不考虑边界 
        n = max(n, x+1),m= max(m, y+1);//更新最大边界 
    }
    for(int i = 1;i <= n;i ++) {
    
    
        for(int j = 1;j <= m; j ++) {
    
    
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j];
        }               
    }
    int ans = 0;

    for (int i = R; i <= n; i ++) {
    
    
        for (int j = R; j <= m; j ++) {
    
    
            ans = max (ans,s[i][j] - s[i - R][j] - s[i][j - R] + s[i -R][j - R]);
        }
    }
    cout << ans << endl;
    return 0;
}

3956. 截断数组

题目链接

思路 :
只需要枚举俩刀即可, 中间部分不用管的 , 只管 左边和右边部分的值是否等于 s[n] / 3 如果是,则加上cnt ++

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,  int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n"
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N  = 100010;
const int M = N * 2;
#define x first
#define y second

int s[N];

void solve () {
    
    
	int n;
    ll ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i ++) {
    
    
        cin >> s[i];
        s[i] += s[i - 1];
    }
    int  t = s[n] / 3;
    if(s[n] % 3 == 0) {
    
     // 因为要把数组均分三份,总和一定得是3的倍数
        for(int i = 1; i < n - 1; i ++) {
    
    
            cnt = 0;
            if(s[i] == t) cnt ++; 
            if(s[n] - s[i + 1] == t) ans += cnt;
        }
    }
    cout << ans << endl;
}

int main(void){
    
    
// 	freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

机器人跳跃

题目链接

  • 题解 (二分 & 递推)https://www.acwing.com/solution/content/90581/
  • ceil(e) 函数 - 》 向上取整!!
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
const int N = 100010;
int h[N];

int main ( ) {
    
    
    int n; 
    cin >> n;
    
    for (int i =1; i <= n; i ++ ) {
    
    
        cin >> h[i];
    }
    double e = 0;
    for(int i = n - 1; i >= 0; i --) {
    
     
// 最多到 n 座建筑 又 h[i + 1]  所以从 n -1 开始
        e = (e + h[i + 1]) / 2;
    }
    cout << ceil(e) << endl;
    return 0;
}



#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
const int N = 100010;
int n; 
int h[N];

bool check(int x) {
    
    
    for (int i =1; i <= n; i ++ ) {
    
    
        x = 2 * x - h[i];
        if(x < 0) return false;
        if(x > 1e5) return true; // 加速退出  不然会TLE
    }
    return true;
}


int main ( ) {
    
    
    
    cin >> n;
    
    for (int i =1; i <= n; i ++ ) {
    
    
        cin >> h[i];
    }
    
    int l = 1, r = 1e5; // 最大范围为题目数据范围
    while(l < r) {
    
    
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << endl; 
    return 0;
}

1

题目链接

思路 :




在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_49486457/article/details/129336418