首页 > 其他分享 >二分

二分

时间:2024-02-05 10:48:06浏览次数:23  
标签:二分 ch int mid read while getchar

二分好题

A. 1.喂养宠物 - 「基础算法」第3章 二分算法强化训练 - 高效进阶 - 课程 - YbtOJ

这是一道简单题。就是我们枚举一下我们选择的\(m\)个兔子,然后求出所有兔子的价值,之后我们排序,从小到大选择。

code:

#include <bits/stdc++.h>
//#define int long long
using namespace std;
inline int read() {
    int x = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return w * x;
}
int n, m;
struct node {
    int v, w;
} a[55];
/*bool cmp(node a,node b){
    if(a.w<b.w)return true;
    else if(a.w==b.w)return a.v<b.v;
    else return false;
}*/
int p[1000];
void pd(int x) {
    memset(p, 0, sizeof(p));
    for (int i = 1; i <= n; i++) p[i] = a[i].v + a[i].w * (x - 1);
    sort(p + 1, p + n + 1);
}
bool check(int mid) {
    int tot = 0;
    pd(mid);
    for (int i = 1; i <= mid; i++) {
        tot += p[i];
        if (tot > m)
            return false;
    }
    // cout<<"!!!!!!!!!!!!!!!!!!!!!!!!"<<tot<<endl;
    return tot <= m;
}
int ans;
int main() {
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i].v = read();
    for (int i = 1; i <= n; i++) a[i].w = read();
    // sort(a+1,a+n+1,cmp);
    int l = 0, r = n;
    // for(int i=1;i<=n;i++)
    // cout<<a[i].v<<" "<<a[i].w<<endl;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) {
            l = mid + 1, ans = mid;
        } else
            r = mid - 1;
    }
    cout << ans << endl;
    return 0;
}

B. 2.最小时间 - 「基础算法」第3章 二分算法强化训练 - 高效进阶 - 课程 - YbtOJ

这道题是A题的一道升级题,同样的思路,只是在上题\(sort\)的时候改为nth-element,就可以A掉这道题,注意题目是不超过\(m\)个物品,所以我们要在每次加的时候都要判断,要不这样我们会WA,只有76分。

nth-element讲解

nth-element的时间复杂度是O(n),所以要比sort快,但在数据小的时候最坏时间复杂度是O(n^2),因为函数原理是随机访问,但实际运用过程中,基本都会是O(n)的时间复杂度。所以说是非常迅速的。
接下来展示一下nth-element的操作:
将第k_th元素放到它该放的位置上,左边元素都小于等于它,右边元素都大于等于它.
有一个序列a,有n个元素,查找第m大个元素,nth-element一般是升序
nth-element(a+1,a+m+1,a+n+1);
但这个不会给你的前面的东西排序
我们可以用一个比较函数来完成
bool operator<(const node &G) const { return val > G.val; }(这是从大到小的)
bool operator<(const node &G) const { return val < G.val; }(这是从小到大的)

code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return w * x;
}
struct node {
    int k, b;
    int val;
    bool operator<(const node &G) const { return val > G.val; }
} a[1000005];
int n, m, s;
int ans;
bool check(int x) {
    for (int i = 0; i < n; i++) a[i].val = a[i].k * x + a[i].b;
    int res = 0;
    nth_element(a, a + m, a + n);
    for (int i = 0; i < m; i++) {
        if (a[i].val > 0)
            res += a[i].val;
        if(res>=s) return true;
    }
    return false;
}
signed main() {
    n = read(), m = read(), s = read();
    for (int i = 0; i < n; i++) a[i].k = read(), a[i].b = read();
    int l = 0, r = 1000000008;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid))
            ans = mid,r = mid - 1;
        else
            l = mid + 1;
    }
    cout << ans << endl;
    return 0;
}

C. 3.攻击法坛 - 「基础算法」第3章 二分算法强化训练 - 高效进阶 - 课程 - YbtOJ

这是一道\(DP+二分\) ,有一说一,我不会,但在我不断学习下,渐渐的懂了。

我们设一个\(L1[i]\) 表示在 \(i\) 这个位置使用长度为 \(j\) 的魔法,\(L2[i]\)表示在 \(i\) 这个位置使用长度为 \(j*2\) 的魔法。\(f[i][j]\)是在使用了\(i\)次第一根法杖,\(j\)次第二根法杖后哪能覆盖到的最远的法坛的序号。

转移方程:

for(int i=0;i<=t1;i++)
for(int j=0;j<=t2;i++){
	if(i!=0) f[i][j] = L1[f[i - 1][j] + 1];
	if(j!=0) f[i][j] = max(f[i][j], L2[f[i][j - 1] + 1])
}

这样我们就能完美的解决这道题

像这种求最小值(最优)的,一定要想到区间DP,这是一种悟性~~,在做题的过程中增长。

code:

#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int N = 2500;
int f[N][N];
int L1[N], L2[N];
inline int read() {
    int x = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return w * x;
}
int n, t1, t2;
int a[N];
int ans;
bool check(int mid) {
    memset(L1, 0, sizeof(L1));
    memset(L2, 0, sizeof(L2));
    memset(f, 0, sizeof(f));
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= n; j++) {
            if (a[j] <= a[i] + mid - 1)
                L1[i] = j;
            if (a[j] <= a[i] + mid * 2 - 1)
                L2[i] = j;
        }
    L1[n + 1] = n;//L1的n+1一定要赋值为n,要不然会在后面的转移方程中会把f[i][j]变成0
    L2[n + 1] = n;//L1的n+1一定要赋值为n,要不然会在后面的转移方程中会把f[i][j]变成0
    for (int i = 0; i <= t1; i++)
        for (int j = 0; j <= t2; j++) {
            if (i != 0)
                f[i][j] = L1[f[i - 1][j] + 1];//在这里会变成0
            if (j != 0)
                f[i][j] = max(f[i][j], L2[f[i][j - 1] + 1]);
        }
    return f[t1][t2] == n;
}
int main() {
    n = read(), t1 = read(), t2 = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    if (t1 + t2 >= n) {//如果我们加起来都大于n了,那我们直接输出1就可以了。
        printf("1");
        return 0;
    }
    sort(a + 1, a + n + 1);
    int l = 0, r = 1e9;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid))
            r = mid - 1, ans = mid;
        else
            l = mid + 1;
    }
    cout << ans << endl;
    return 0;
}

D. X.分割矩阵 - 「基础算法」第3章 二分算法强化训练 - 高效进阶 - 课程 - YbtOJ

好,这是一道好题。

数组划分的二维拓展,我们可以先扫行,再扫列。这道题还要用到贪心的思想。

二维的题一定要从行列中分别考虑,但也有的题要转换建图,这是我们在这里不讨论的。

我们知道如果我们选择了第i行开始割,那我们就绝对不会选择i+1行,因为这样一定不优,接着我们用一个sum数组来存储
该行的价值,如果他的价值到达了我们可以割的界限,那我们就把它给割掉,但我们在中间会出现其中一个很大的现象,那
我们就要仔细处理一下,这时候我们可以再考虑我们的列,如果我们这列大于mid,我们就割,这就是贪心。最后我们查询
是不是割的行数是A,割的列数是B。

code:

#include <bits/stdc++.h>
//#define int long long
using namespace std;
inline int read() {
    int x = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return w * x;
}
int n, m, A, B;
int a[505][505], sum[505][505];
bool f(int L, int r, int x) {
    int cnt = 0, s = 0;
    for (int j = 1; j <= m; j++) {
        s += sum[r][j] - sum[L - 1][j];
        if (s >= x) {//大于就割
            cnt++;
            s = 0;
        }
    }
    if (cnt < B)
        return false;
    return true;
}
bool check(int mid) {
    int cnt = 0, L = 1;
    for (int i = 1; i <= n; i++) {
        if (f(L, i, mid)) {//可割
            cnt++;
            L = i + 1;
        }
    }
    if (cnt < A)
        return false;
    return true;
}
int ans;
int main() {
    n = read(), m = read(), A = read(), B = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            a[i][j] = read();
            sum[i][j] = sum[i - 1][j] + a[i][j];
        }
    int l = 0, r;
    for (int j = 1; j <= m; j++) r += sum[n][j];
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid))
            l = mid + 1, ans = mid;
        else
            r = mid - 1;
    }
    cout << ans << endl;
    return 0;
}

将停一段时间,因为我的图论太差了/kk

标签:二分,ch,int,mid,read,while,getchar
From: https://www.cnblogs.com/qlwybz/p/18007515

相关文章

  • 二分查找BinarySearch
    二分查找法首先,整个数组必须有序,通常为递增。将数组中间数字与被比较元素比较相等即目标元素为被比较元素中间元素大于目标元素,意味着中间元素右边的所有元素均大于目标元素,排除中间元素小于目标元素,意味着中间元素左边的所有元素均小于目标元素,排除当数组元......
  • 【学习笔记】网络流与二分图初步
    网络流与二分图初步我们约定,对于有向图\(G=(V,E)\),分析复杂度时\(m=|E|,n=|V|\)。在分析时间复杂度时,网络流的实际表现基本都优于其理论上的时间复杂度表现。I概念(1)网络流:在一个有向带权图上(不考虑自环和重边),与最短路类似,我们定义一个源点\(s\)和一个汇点\(t\)......
  • 线段树二分——nc2.4多校_G.新春漫步
    目录问题概述思路分析参考代码做题反思问题概述原题参考G.新春漫步坐标轴上有n个点,初始时每个位置上都有一个坚固程度为a1的障碍物,接下来有m次操作1.将位置p上的障碍物的坚固程度减去x,若减去x后坚固程度小于等于0,则该障碍物消失2.询问一个人从p的位置向右走,最多能走到什么位......
  • 代码随想录算法训练营第一天 | 27. 移除元素 | 704. 二分查找
     704.二分查找 已解答简单 相关标签相关企业 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例1:输入:numstarget输出:解释:nums......
  • 基础算法(十四)离散化+二分 ---以题为例
    假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。输入格式第一行包含两个整数 n 和 m。接下来 ......
  • 闭着眼睛写二分搜索
    本文就来探究几个最常用的二分查找场景:寻找一个数、寻找左侧边界、寻找右侧边界。而且,我们就是要深入细节,比如不等号是否应该带等号,mid是否应该加一等等。分析这些细节的差异以及出现这些差异的原因,保证你能灵活准确地写出正确的二分查找算法。另外再声明一下,对于二分搜索的每......
  • 费用流求解二分图最大权匹配
    二分图最大权匹配问题:有\(n_1\)个左部点,\(n_2\)个右部点,\(m\)条边,边有边权\(w_i\),表示若选择这条边就会获得\(w_i\)的收益,求获得收益最大的一种图的匹配方案。若考虑用费用流求解,建立超级源点\(S\)和超级汇点\(T\),\(S\)向每个左部点连边,流量1费用0;每个右部点向\(......
  • 二分答案
    二分法简介为一高效查找方法,将搜索范围一分为二。适用于有序数据集合,利用单调性减少不必要的枚举。解题步骤研究数据结构的单调性。确定最大区间[L,R],确保分界点一定在里头,若以R为答案,区间为[L+1,R](若为0到n,则L=-1,R=n),若以L为答案,答案区间为[L,R-1](同理)。可以参照二分查找lo......
  • 【洛谷 P2249】【深基13.例1】查找(向量+二分查找+递归)
    【深基13.例1】查找题目描述输入个不超过的单调不减的(就是后面的数字不小于前面的数字)非负整数,然后进行次询问。对于每次询问,给出一个整数,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出。输入格式第一行个整数和,表示数字个数和询问次数。第二行......
  • 二分查找!
    使用范围:查找元素:在有序数组中查找一个特定的元素。找到边界:查找有序数组中某个值的第一个或最后一个出现的位置。搜索旋转排序数组:在旋转排序数组中查找一个特定的元素。查找峰值元素:在数组中查找峰值元素。求平方根:计算一个非负整数的平方根。搜索区间:......