• 寒假训练——第一周(二分)


    A - 栅栏

    A - 栅栏

    思路:

    二分 + D F S DFS DFS + 剪枝

    总体思路如下:

    1. m i d mid mid 为最多可以剪出的木材数(升序排列)
    2. 按照每一个 m i d mid mid 判断是否可以完成,若 t r u e true true,则 l = m i d l = mid l=mid;反之, r = m i d − 1 r = mid - 1 r=mid1

    剪枝:

    1. 优化搜索顺序:木材( s m a l l small small) 从从大到小枚举,木板( b i g big big ) 从小到大枚举,产生的分支数量较少
    2. 可行性剪枝 :( s u m sum sum s m a l l [ m ] small[m] small[m] <= s u m sum sum b i g [ n ] big[n] big[n] )
    3. 可行性剪枝:若 s u m sum sum b i g big big − - w a s t e waste waste < < < s u m sum sum s m a l l [ m i d ] small[mid] small[mid]
    4. 排除等效冗余: s m a l l [ k ] small[k] small[k] = s a m l l [ k − 1 ] samll[k-1] samll[k1],继续从当前位置开始枚举

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int unsigned int
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 55, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int n, m;
    int big[N], small[M], sum_small[M];
    int sum_big;
    int waste;
    
    int mid;
    
    bool dfs(int k, int now)
    {
        if(k == 0) return true; // 成立
        if(sum_big - waste < sum_small[mid]) return false; // 3. 可行性剪枝
        
        bool f = 0;
        
        for (int i = now; i <= n; i ++ )
        {
            if(big[i] >= small[k])
            {
                big[i] -= small[k];
                if(big[i] < small[1]) waste += big[i];
                if(small[k - 1] == small[k]) f = dfs(k - 1, i); // 4. 排除等效冗余
                else f = dfs(k - 1, 1);
                
                // 恢复现场
                if(big[i] < small[1]) waste -= big[i];
                big[i] += small[k];
                
                if(f) return true;
            }
        }
        return false;
    }
    
    void solve()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ )
            cin >> big[i], sum_big += big[i];
        
        sort(big + 1, big + n + 1);
        
        cin >> m;
        for (int i = 1; i <= m; i ++ )
            cin >> small[i];
        
        sort(small + 1, small + m + 1);
        
        for (int i = 1; i <= m; i ++ )
            sum_small[i] = sum_small[i - 1] + small[i];
        
        while(sum_small[m] > sum_big) m --; // 2. 可行性剪枝
        
        int l = 0, r = m;
        while(l < r)
        {
            mid = l + r + 1>> 1;
            if(dfs(mid, 1)) l = mid; // 1. 优化搜索顺序
            else r = mid - 1;
        }
        
        cout << l << endl;
        
        return;
    }
    
    signed main()
    {
        fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    B - 扑克牌

    B - 扑克牌

    思路:

    二分答案

    1. m i d mid mid 为所求扑克牌的套数
    2. 可用的 j o k e r joker joker 数目为 m i n ( m i d , m ) min(mid, m) min(mid,m) 判断是否超出所用 j o k e r joker joker 的数目
    3. 若没超出 l = m i d l = mid l=mid ;反之, r = m i d − 1 r = mid - 1 r=mid1

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int long long
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 55, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int n, m;;
    int a[N];
    
    bool check(int x)
    {
        int res = 0;
        int s = min(x, m);
        for (int i = 1; i <= n; i ++ )
        {
            if(a[i] < x) res += x - a[i];
            if(res > s) return false;
        }
        return true;
    }
    
    void solve()
    {
        cin >> n >> m;
        
        for (int i = 1; i <= n; i ++ )
            cin >> a[i];
            
        int l = 1, r = 1e9;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(check(mid)) l = mid;
            else r = mid - 1;
        }
        
        cout << l << endl;
        
        return;
    }
    
    signed main()
    {
        fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    C - 跳石头

    C - 跳石头

    思路:

    二分答案

    1. m i d mid mid 为跳跃距离的最大值
    2. a [ i ] a[i] a[i] 与 上一个石子 a [ l a s t ] a[last] a[last] 距离小于 m i d mid mid r e s + + res ++ res++
    3. r e s > m res > m res>m m i d mid mid 过小, l = m i d l = mid l=mid;反之 r = m i d r = mid r=mid

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int long long
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 50010, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int n, m, len;
    int a[N];
    
    bool check(int x)
    {
        int res = 0;
        int last = 0;
        for (int i = 1; i <= n; i ++ )
        {
            if(a[i] - a[last] < x) res ++;
            else last = i;
            if(res > m) return false;
        }
        return true;
    }
    
    void solve()
    {
        cin >> len >> n >> m;
        
        for (int i = 1; i <= n; i ++ )
            cin >> a[i];
        
        int l = 0, r = len;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(check(mid)) l = mid;
            else r = mid - 1;
        }
        
        cout << r << endl;
        
        return;
    }
    
    signed main()
    {
        fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    D - 小车问题

    D - 小车问题

    思路:

    浮点数二分答案:

    1. 甲的总时间为:车 t i m e time time + 人 t i m e time time;乙的总时间为:人 t i m e time time + 车 t i m e time time,若时间最短,则甲乙同时到终点
    2. m i d mid mid 表示 甲坐车走的距离,根据距离算甲乙的时间
    3. 若 甲 t i m e time time > 乙 t i m e time time m i d mid mid 太小, l = m i d l = mid l=mid; 反之, m i d mid mid 太大, r = m i d r = mid r=mid

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int long long
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 50010, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int n, m, len;
    int a[N];
    
    bool check(double x)
    {
        double atime = x / m + (len - x) / n;
        double bt = x / m + (x - x / m * n) / (m + n) ;
        double btime = bt + (len - bt * n) / m;
        
        //cout << atime << " " << btime << endl;
        
        if(btime > atime) return true;
        else return false;
    }
    
    void solve()
    {
        scanf("%d%d%d", &len, &n, &m);
        
        double l = 0, r = len;
        while( fabs(l - r) > eps )
        {
            double mid = (l + r) / 2;
            if(check(mid)) r = mid;
            else l = mid;
        }
        
        double res = l / m + (len - l) / n;
        
        printf("%.2lf\n", res);
        
        return;
    }
    
    signed main()
    {
        //fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    E - 切绳子

    E - 切绳子

    思路:

    浮点数二分答案:

    1. 查找最小长度的最大值(左半区间的右端点)
    2. m i d mid mid 表示为绳子的长度
    3. m i d mid mid <= a n s ans ans (即、 r e s > = m res >= m res>=m) ,此时 l l l 向右移动, l = m i d l = mid l=mid
    4. 反之, r = m i d r = mid r=mid

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int long long
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 10010, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-9;
    
    int n, m, len;
    double a[N];
    
    bool check(double x)
    {
        int res = 0;
        for (int i = 1; i <= n; i ++ )
        {
            res += floor(a[i] / x);
        }
    
        if(res >= m) return true;
        else return false;
    }
    
    void solve()
    {
        scanf("%lld %lld", &n, &m);
        
        for (int i = 1; i <= n; i ++ )
            scanf("%lf", &a[i]);
        
        double l = 0, r = 1e9;
        while( fabs(r - l) > eps )
        {
            double mid = (l + r) / 2;
            if(check(mid)) l = mid;
            else r = mid;
        }
        
        printf("%.6f\n", r);
        
        return;
    }
    
    signed main()
    {
        //fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    F - 奶牛晒衣服

    F - 奶牛晒衣服

    思路:

    二分答案

    1. 查找最大的最小值(即,右区间的左端点)
    2. m i d mid mid 为所用时间,用 r = m i d , l = m i d + 1 r = mid, l = mid + 1 r=mid,l=mid+1 模板
    3. r e s < = m i d res <= mid res<=mid 即、 m i d mid mid 太小, r = m i d r = mid r=mid;反之, l = m i d + 1 l = mid + 1 l=mid+1

    代码如下:

    #include 
    
    #define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
    
    #define x first
    #define y second
    #define int long long
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 5e5 + 10, M = 1010, null = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-9;
    
    int n, m1, m2;
    int a[N];
    
    bool check(int x)
    {
        int res = 0;
        for (int i = 1; i <= n; i ++ )
        {
            int j = a[i] - m1 * x;
            if(j > 0) res += j / m2 + (j % m2 != 0);
            if(res > x) return false;
        }
        
        return true;
    }
        
    void solve()
    {
        cin >> n >> m1 >> m2;
        
        for (int i = 1; i <= n; i ++ )
            cin >> a[i];
        
        int l = 1, r = 1e9;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        
        cout << r << endl;
        
        return;
    }
    
    signed main()
    {
        //fast;
        int T = 1; 
        //cin >> T;
        while(T -- )
            solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    mysql 中的锁
    Day05
    【在线教育】EasyExcel入门
    【web-代码审计】(14.1)代码审查方法
    2022-9-20-C++11新特性
    【数据结构】排序1——排序的概述分类、存储结构定义
    QtDay4
    js获取当前月第一天最后一天
    http进一步认识
    【19】c++设计模式——>桥接模式
  • 原文地址:https://blog.csdn.net/m0_61409183/article/details/126386168